Skip to content

Commit 89b20fe

Browse files
authored
Merge pull request #71 from Materials-Data-Science-and-Informatics/feature/add-fortran-support
Add fortran support
2 parents 1fd7ad0 + bc5c5a3 commit 89b20fe

16 files changed

Lines changed: 512 additions & 38 deletions

File tree

.somesy.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ no_sync_codemeta = false
7676
codemeta_file = "codemeta.json"
7777
no_sync_package_json = true
7878
no_sync_julia = true
79+
no_sync_fortran = true
7980
show_info = false
8081
verbose = false
8182
debug = true

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Please consult the changelog to inform yourself about breaking changes and secur
88

99
* added separate `documentation` URL to Project metadata model
1010
* added support for Julia `Project.toml` file
11+
* added support for fortran `fpm.toml` file
1112

1213
## [v0.3.1](https://github.com/Materials-Data-Science-and-Informatics/somesy/tree/v0.3.1) <small>(2024-01-23)</small> { id="0.3.1" }
1314

README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ verbose = true # show detailed information about what somesy is doing
109109
<!-- --8<-- [end:somesytoml] -->
110110

111111
Alternatively, you can also add the somesy configuration to an existing
112-
`pyproject.toml`, `package.json` or `Project.toml` file. The somesy [manual](https://materials-data-science-and-informatics.github.io/somesy/main/manual/#somesy-input-file) contains examples showing how to do that.
112+
`pyproject.toml`, `package.json`, `Project.toml`, or `fpm.toml` file. The somesy [manual](https://materials-data-science-and-informatics.github.io/somesy/main/manual/#somesy-input-file) contains examples showing how to do that.
113113

114114
### Using somesy
115115

@@ -125,7 +125,7 @@ authoritative** source for project metadata, which is used to update all
125125
supported (and enabled) *target files*. You can find an overview of supported
126126
formats further below.
127127

128-
By default, `somesy` will create (if they did not exist) or update `CITATION.cff` and `codemeta.json` files in your repository. If you happen to use `pyproject.toml` (in Python projects), `package.json` (in JavaScript projects), or `Project.toml` (in Julia projects), somesy would also update the respective information there.
128+
By default, `somesy` will create (if they did not exist) or update `CITATION.cff` and `codemeta.json` files in your repository. If you happen to use `pyproject.toml` (in Python projects), `package.json` (in JavaScript projects), `Project.toml` (in Julia projects), or `fpm.toml` (in Fortran projects) somesy would also update the respective information there.
129129

130130
You can see call available options with `somesy --help`,
131131
all of these can also be conveniently set in your `somesy.toml` file.
@@ -168,16 +168,18 @@ Here is an overview of all the currently supported files and formats.
168168
| -------------- | ------ |-| ----------------------------- | ------ |
169169
| (.)somesy.toml | ✓ | | pyproject.toml _(poetry)_ | ✓ |
170170
| pyproject.toml | ✓ | | pyproject.toml _(setuptools)_ | ✓(1.) |
171-
| package.json | ✓ | | package.json | ✓(2.) |
172-
| Project.toml | ✓ | | Project.toml | ✓ |
171+
| package.json | ✓ | | package.json _(JavaScript)_ | ✓(2.) |
172+
| Project.toml | ✓ | | Project.toml _(Julia)_ | ✓ |
173+
| fpm.toml | ✓ | | fpm.toml _(Fortran)_ | ✓(3.) |
173174
| | | | CITATION.cff | ✓ |
174-
| | | | codemeta.json | ✓(3.) |
175+
| | | | codemeta.json | ✓(4.) |
175176

176177
**Notes:**
177178

178179
1. note that `somesy` does not support setuptools *dynamic fields*
179180
2. `package.json` only supports one author, so `somesy` will pick the *first* listed author
180-
3. unlike other targets, `somesy` will *re-create* the `codemeta.json` (i.e. do not edit it by hand!)
181+
3. `fpm.toml` only supports one author and maintainer, so `somesy` will pick the *first* listed author and maintainer
182+
4. unlike other targets, `somesy` will *re-create* the `codemeta.json` (i.e. do not edit it by hand!)
181183

182184
<!-- --8<-- [end:quickstart] -->
183185

docs/manual.md

Lines changed: 63 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -117,33 +117,33 @@ some of the currently supported formats. Bold field names are mandatory, the oth
117117

118118
=== "Person Metadata"
119119

120-
| Somesy Field | Poetry Config | SetupTools Config | Julia Config | package.json | CITATION.cff | CodeMeta |
121-
| ---------------- | ------------- | ----------------- | ------------ | ------------ | --------------- | --------------- |
122-
| | | | | | | |
123-
| **given-names** | name+email | name | name+email | name | given-names | givenName |
124-
| **family-names** | name+email | name | name+email | name | family-names | familyName |
125-
| **email** | name+email | email | name+email | email | email | email |
126-
| orcid | - | - | - | url | orcid | id |
127-
| *(many others)* | - | - | - | - | *(same)* | *(same)* |
120+
| Somesy Field | Poetry Config | SetupTools Config | Julia Config | Fortran Config | package.json | CITATION.cff | CodeMeta |
121+
| ---------------- | ------------- | ----------------- | ------------ | -------------- | ------------ | --------------- | --------------- |
122+
| | | | | | | | |
123+
| **given-names** | name+email | name | name+email | name+email | name | given-names | givenName |
124+
| **family-names** | name+email | name | name+email | name+email | name | family-names | familyName |
125+
| **email** | name+email | email | name+email | name+email | email | email | email |
126+
| orcid | - | - | - | - | url | orcid | id |
127+
| *(many others)* | - | - | - | - | - | *(same)* | *(same)* |
128128

129129
=== "Project Metadata"
130130

131-
| Somesy Field | Poetry Config | SetupTools Config | Julia Config | package.json | CITATION.cff | CodeMeta |
132-
| ----------------- | ------------- | ------------------ | ------------ | ------------ | --------------- | ----------------- |
133-
| | | | | | |
134-
| **name** | name | name | name | name | title | name |
135-
| **description** | description | description | - | description | abstract | description |
136-
| **license** | license | license | - | license | license | license |
137-
| **version** | version | version | version | version | version | version |
138-
| | | | | | | |
139-
| ***author=true*** | authors | authors | authors | author | authors | author |
140-
| *maintainer=true* | maintainers | maintainers | - | maintainers | contact | maintainer |
141-
| *people* | - | - | - | contributors | - | contributor |
142-
| | | | | | | |
143-
| keywords | keywords | keywords | - | keywords | keywords | keywords |
144-
| homepage | homepage | urls.homepage | - | homepage | url | url |
145-
| repository | repository | urls.repository | - | repository | repository_code | codeRepository |
146-
| documentation | documentation | urls.documentation | - | - | - | buildInstructions |
131+
| Somesy Field | Poetry Config | SetupTools Config | Julia Config | Fortran Config | package.json | CITATION.cff | CodeMeta |
132+
| ----------------- | ------------- | ------------------ | ------------ | -------------- | ------------ | --------------- | ----------------- |
133+
| | | | | | | |
134+
| **name** | name | name | name | name | name | title | name |
135+
| **description** | description | description | - | description | description | abstract | description |
136+
| **license** | license | license | - | license | license | license | license |
137+
| **version** | version | version | version | version | version | version | version |
138+
| | | | | | | | |
139+
| ***author=true*** | authors | authors | authors | author | author | authors | author |
140+
| *maintainer=true* | maintainers | maintainers | - | maintainer | maintainers | contact | maintainer |
141+
| *people* | - | - | - | - | contributors | - | contributor |
142+
| | | | | | | | |
143+
| keywords | keywords | keywords | - | keywords | keywords | keywords | keywords |
144+
| homepage | homepage | urls.homepage | - | homepage | homepage | url | url |
145+
| repository | repository | urls.repository | - | - | repository | repository_code | codeRepository |
146+
| documentation | documentation | urls.documentation | - | - | - | - | buildInstructions |
147147

148148
Note that the mapping is often not 1-to-1. For example, CITATION.cff allows rich
149149
specification of author contact information and complex names. In contrast,
@@ -171,6 +171,7 @@ Without an input file specifically provided, somesy will check if it can find a
171171
* `somesy.toml`
172172
* `pyproject.toml` (in `tool.somesy` section)
173173
* `Project.toml` (in `tool.somesy` section)
174+
* `fpm.toml` (in `tool.somesy` section)
174175
* `package.json` (in `somesy` section)
175176

176177
which is located in the current working directory. If you want to provide
@@ -260,6 +261,40 @@ one of the supported input formats:
260261
verbose = true # show detailed information about what somesy is doing
261262
```
262263

264+
=== "fpm.toml"
265+
```toml
266+
name = "my-amazing-project"
267+
version = "0.1.0"
268+
269+
[tool.somesy.project]
270+
name = "my-amazing-project"
271+
version = "0.1.0"
272+
description = "Brief description of my amazing software."
273+
274+
keywords = ["some", "descriptive", "keywords"]
275+
license = "MIT"
276+
repository = "https://github.com/username/my-amazing-project"
277+
278+
# This is you, the proud author of your project
279+
[[tool.somesy.project.people]]
280+
given-names = "Jane"
281+
family-names = "Doe"
282+
email = "j.doe@example.com"
283+
orcid = "https://orcid.org/0000-0000-0000-0001"
284+
author = true # is a full author of the project (i.e. appears in citations)
285+
maintainer = true # currently maintains the project (i.e. is a contact person)
286+
287+
# this person is a acknowledged contributor, but not author or maintainer:
288+
[[tool.somesy.project.people]]
289+
given-names = "Another"
290+
family-names = "Contributor"
291+
email = "a.contributor@example.com"
292+
orcid = "https://orcid.org/0000-0000-0000-0002"
293+
294+
[tool.somesy.config]
295+
verbose = true # show detailed information about what somesy is doing
296+
```
297+
263298
=== "package.json"
264299

265300
```json
@@ -412,6 +447,10 @@ Therefore, **in such a case you will need to fix the ORCID in all configured som
412447
before running somesy (so somesy will not create new person entries), or
413448
after running somesy (to remove the duplicate entries with the incorrect ORCID).
414449

450+
!!! warning
451+
452+
Person identification and merging is not applied to standards with free text fields for authors or maintainers, such as `fpm.toml`.
453+
415454
### Codemeta
416455

417456
While `somesy` is modifying existing files for most supported formats and implements

src/somesy/cli/init.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ def config():
6363
if julia_file is not None or julia_file != "":
6464
options["julia_file"] = julia_file
6565

66+
options["no_sync_fortran"] = not typer.confirm(
67+
"Do you want to sync to a fpm.toml(fortran) file?", default=True
68+
)
69+
fortran_file = typer.prompt("fpm.toml(fortran) file path", default="fpm.toml")
70+
if fortran_file is not None or fortran_file != "":
71+
options["fortran_file"] = fortran_file
72+
6673
options["show_info"] = typer.confirm(
6774
"Do you want to show info about the sync process?"
6875
)

src/somesy/cli/sync.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,13 @@ def sync(
104104
no_sync_julia: bool = typer.Option(
105105
None,
106106
"--no-sync-julia",
107-
"-M",
108-
help="Do not sync Project.toml(Julia) file",
107+
"-L",
108+
help="Do not sync Project.toml(Julia) file (default: False)",
109109
),
110110
julia_file: Path = typer.Option(
111111
None,
112112
"--julia-file",
113-
"-m",
113+
"-l",
114114
exists=True,
115115
file_okay=True,
116116
dir_okay=False,
@@ -119,6 +119,24 @@ def sync(
119119
resolve_path=True,
120120
help="Custom Project.toml(Julia) file path",
121121
),
122+
no_sync_fortran: bool = typer.Option(
123+
None,
124+
"--no-sync-fortran",
125+
"-F",
126+
help="Do not sync fpm.toml(fortran) file (default: False)",
127+
),
128+
fortran_file: Path = typer.Option(
129+
None,
130+
"--fortran-file",
131+
"-f",
132+
exists=True,
133+
file_okay=True,
134+
dir_okay=False,
135+
writable=True,
136+
readable=True,
137+
resolve_path=True,
138+
help="Custom fpm.toml(fortran) file path",
139+
),
122140
):
123141
"""Sync project metadata input with metadata files."""
124142
somesy_input = resolved_somesy_input(
@@ -133,6 +151,8 @@ def sync(
133151
codemeta_file=codemeta_file,
134152
no_sync_julia=no_sync_julia,
135153
julia_file=julia_file,
154+
no_sync_fortran=no_sync_fortran,
155+
fortran_file=fortran_file,
136156
)
137157
run_sync(somesy_input)
138158

@@ -156,6 +176,14 @@ def run_sync(somesy_input: SomesyInput):
156176
logger.info(
157177
f" - [italic]codemeta.json[/italic]:\t[grey]{conf.codemeta_file}[/grey]\n"
158178
)
179+
if not conf.no_sync_julia:
180+
logger.info(
181+
f" - [italic]Project.toml(Julia)[/italic]:\t[grey]{conf.julia_file}[/grey]"
182+
)
183+
if not conf.no_sync_fortran:
184+
logger.info(
185+
f" - [italic]fpm.toml(fortran)[/italic]:\t[grey]{conf.fortran_file}[/grey]"
186+
)
159187
# ----
160188
sync_command(somesy_input)
161189
# ----

src/somesy/commands/sync.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from somesy.cff.writer import CFF
88
from somesy.codemeta import Codemeta
99
from somesy.core.models import ProjectMetadata, SomesyInput
10+
from somesy.fortran.writer import Fortran
1011
from somesy.julia.writer import Julia
1112
from somesy.package_json.writer import PackageJSON
1213
from somesy.pyproject.writer import Pyproject
@@ -40,6 +41,9 @@ def sync(somesy_input: SomesyInput):
4041
if not conf.no_sync_julia:
4142
_sync_julia(metadata, conf.julia_file)
4243

44+
if not conf.no_sync_fortran:
45+
_sync_fortran(metadata, conf.fortran_file)
46+
4347

4448
def _sync_python(
4549
metadata: ProjectMetadata,
@@ -120,7 +124,7 @@ def _sync_julia(
120124
"""Sync Project.toml file using project metadata.
121125
122126
Args:
123-
metadata (ProjectMetadata): project metadata to sync pyproject.toml file.
127+
metadata (ProjectMetadata): project metadata to sync Project.toml file.
124128
julia_file (Path, optional): Project.toml file path if wanted to be synced. Defaults to None.
125129
"""
126130
logger.verbose("Loading Project.toml file.")
@@ -129,3 +133,21 @@ def _sync_julia(
129133
cm.sync(metadata)
130134
cm.save()
131135
logger.verbose(f"Saved synced Project.toml file to {julia_file}.")
136+
137+
138+
def _sync_fortran(
139+
metadata: ProjectMetadata,
140+
fortran_file: Path,
141+
):
142+
"""Sync fpm.toml file using project metadata.
143+
144+
Args:
145+
metadata (ProjectMetadata): project metadata to sync fpm.toml file.
146+
fortran_file (Path, optional): fpm.toml file path if wanted to be synced. Defaults to None.
147+
"""
148+
logger.verbose("Loading fpm.toml file.")
149+
cm = Fortran(fortran_file)
150+
logger.verbose("Syncing fpm.toml file.")
151+
cm.sync(metadata)
152+
cm.save()
153+
logger.verbose(f"Saved synced fpm.toml file to {fortran_file}.")

src/somesy/core/core.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"pyproject.toml",
1515
"package.json",
1616
"Project.toml",
17+
"fpm.toml",
1718
]
1819
"""Input files ordered by priority for discovery."""
1920

@@ -78,9 +79,10 @@ def get_input_content(path: Path, *, no_unwrap: bool = False) -> Dict[str, Any]:
7879
return ret if no_unwrap else ret.unwrap()
7980

8081
# pyproject.toml
81-
if (
82-
path.suffix == ".toml" and "pyproject" in path.name
83-
) or path.name == "Project.toml":
82+
if (path.suffix == ".toml" and "pyproject" in path.name) or path.name in [
83+
"Project.toml",
84+
"fpm.toml",
85+
]:
8486
with open(path, "r") as f:
8587
input_content = tomlkit.load(f)
8688
if "tool" in input_content and "somesy" in input_content["tool"]:

src/somesy/core/models.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def model_dump_json(self, *args, **kwargs):
119119
return json.dumps(ret, ensure_ascii=False)
120120

121121

122-
_SOMESY_TARGETS = ["cff", "pyproject", "package_json", "codemeta", "julia"]
122+
_SOMESY_TARGETS = ["cff", "pyproject", "package_json", "codemeta", "julia", "fortran"]
123123

124124

125125
class SomesyConfig(SomesyBaseModel):
@@ -190,6 +190,13 @@ def at_least_one_target(cls, values):
190190
"Project.toml"
191191
)
192192

193+
no_sync_fortran: Annotated[
194+
bool, Field(description="Do not sync with fpm.toml.")
195+
] = False
196+
fortran_file: Annotated[Path, Field(description="fpm.toml file path.")] = Path(
197+
"fpm.toml"
198+
)
199+
193200
def log_level(self) -> SomesyLogLevel:
194201
"""Return log level derived from this configuration."""
195202
return SomesyLogLevel.from_flags(

src/somesy/fortran/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
"""Fortran module."""
2+
from .writer import Fortran
3+
4+
__all__ = ["Fortran"]

0 commit comments

Comments
 (0)