From 4fb523fbd04770a0b8eb7741c0150b1f85dd27d4 Mon Sep 17 00:00:00 2001 From: Mustafa Soylu Date: Wed, 14 Feb 2024 17:19:53 +0100 Subject: [PATCH 1/6] add fortran module --- src/somesy/fortran/__init__.py | 4 ++ src/somesy/fortran/models.py | 65 ++++++++++++++++++ src/somesy/fortran/writer.py | 121 +++++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+) create mode 100644 src/somesy/fortran/__init__.py create mode 100644 src/somesy/fortran/models.py create mode 100644 src/somesy/fortran/writer.py diff --git a/src/somesy/fortran/__init__.py b/src/somesy/fortran/__init__.py new file mode 100644 index 00000000..1c845e06 --- /dev/null +++ b/src/somesy/fortran/__init__.py @@ -0,0 +1,4 @@ +"""Fortran module.""" +from .writer import Fortran + +__all__ = ["Fortran"] diff --git a/src/somesy/fortran/models.py b/src/somesy/fortran/models.py new file mode 100644 index 00000000..90ef8a0f --- /dev/null +++ b/src/somesy/fortran/models.py @@ -0,0 +1,65 @@ +"""Pyproject models.""" +from typing import Optional, Set + +from packaging.version import parse as parse_version +from pydantic import ( + BaseModel, + Field, + field_validator, +) +from typing_extensions import Annotated + +from somesy.core.types import HttpUrlStr + + +class FortranConfig(BaseModel): + """Fortran configuration model.""" + + model_config = dict(use_enum_values=True) + + name: Annotated[ + str, + Field(pattern=r"^[A-Za-z0-9]+([_-][A-Za-z0-9]+)*$", description="Package name"), + ] + version: Annotated[ + Optional[str], + Field( + pattern=r"^\d+(\.\d+)*((a|b|rc)\d+)?(post\d+)?(dev\d+)?$", + description="Package version", + ), + ] = None + description: Annotated[ + Optional[str], Field(description="Package description") + ] = None + license: Annotated[ + Optional[str], + Field(description="SPDX license identifier(s)."), + ] = None + author: Annotated[ + Optional[str], Field(description="Package author information") + ] = None + maintainer: Annotated[ + Optional[str], Field(description="Package maintainer information") + ] = None + copyright: Annotated[ + Optional[str], Field(description="Package copyright text") + ] = None + homepage: Annotated[ + Optional[HttpUrlStr], Field(description="Package homepage") + ] = None + keywords: Annotated[ + Optional[Set[str]], Field(description="Keywords that describe the package") + ] = None + categories: Annotated[ + Optional[Set[str]], Field(description="Categories that package falls into") + ] = None + + @field_validator("version") + @classmethod + def validate_version(cls, v): + """Validate version using PEP 440.""" + try: + _ = parse_version(v) + except ValueError as err: + raise ValueError("Invalid version") from err + return v diff --git a/src/somesy/fortran/writer.py b/src/somesy/fortran/writer.py new file mode 100644 index 00000000..6aa7f2e7 --- /dev/null +++ b/src/somesy/fortran/writer.py @@ -0,0 +1,121 @@ +"""Fortran writer.""" +import logging +from pathlib import Path +from typing import Any, List, Optional + +import tomlkit +from rich.pretty import pretty_repr + +from somesy.core.models import Person, ProjectMetadata +from somesy.core.writer import FieldKeyMapping, IgnoreKey, ProjectMetadataWriter + +from .models import FortranConfig + +logger = logging.getLogger("somesy") + + +class Fortran(ProjectMetadataWriter): + """Fortran config file handler parsed from fpm.toml.""" + + def __init__(self, path: Path): + """Fortran config file handler parsed from fpm.toml. + + See [somesy.core.writer.ProjectMetadataWriter.__init__][]. + """ + mappings: FieldKeyMapping = { + "authors": ["author"], + "maintainers": ["maintainer"], + "documentation": IgnoreKey(), + } + super().__init__(path, create_if_not_exists=False, direct_mappings=mappings) + + @property + def authors(self): + """Return the only author of the fpm.toml file as list.""" + authors = [] + try: + self._to_person(self._get_property(self._get_key("authors"))) + authors = [self._get_property(self._get_key("authors"))] + except ValueError: + logger.warning("Cannot convert authors to Person object.") + return authors + + @authors.setter + def authors(self, authors: List[Person]) -> None: + """Set the authors of the project.""" + authors = self._from_person(authors[0]) + self._set_property(self._get_key("authors"), authors) + + @property + def maintainers(self): + """Return the only author of the fpm.toml file as list.""" + maintainers = self._get_property(self._get_key("maintainers")) + if maintainers: + return [self._get_property(self._get_key("maintainers"))] + return [] + + @maintainers.setter + def maintainers(self, maintainers: List[Person]) -> None: + """Set the maintainers of the project.""" + maintainers = self._from_person(maintainers[0]) + self._set_property(self._get_key("maintainers"), maintainers) + + def _load(self) -> None: + """Load fpm.toml file.""" + with open(self.path) as f: + self._data = tomlkit.load(f) + + def _validate(self) -> None: + """Validate poetry config using pydantic class. + + In order to preserve toml comments and structure, tomlkit library is used. + Pydantic class only used for validation. + """ + config = dict(self._get_property([])) + logger.debug( + f"Validating config using {FortranConfig.__name__}: {pretty_repr(config)}" + ) + FortranConfig(**config) + + def save(self, path: Optional[Path] = None) -> None: + """Save the fpm file.""" + path = path or self.path + with open(path, "w") as f: + tomlkit.dump(self._data, f) + + @staticmethod + def _from_person(person: Person): + """Convert project metadata person object to poetry string for person format "full name .""" + return person.to_name_email_string() + + @staticmethod + def _to_person(person_obj: Any) -> Person: + """Cannot convert from free string to person object.""" + try: + return Person.from_name_email_string(person_obj) + except ValueError: + logger.warning(f"Cannot convert {person_obj} to Person object.") + return None + + def sync(self, metadata: ProjectMetadata) -> None: + """Sync output file with other metadata files.""" + self.name = metadata.name + self.description = metadata.description + + if metadata.version: + self.version = metadata.version + + if metadata.keywords: + self.keywords = metadata.keywords + + self.authors = metadata.authors() + maintainers = metadata.maintainers() + + # set if not empty + if maintainers: + # only one maintainer is allowed + self.maintainers = maintainers + + self.license = metadata.license.value + + self.homepage = str(metadata.homepage) if metadata.homepage else None From 2eea9cf558ad042d737b67aaaed86710d52d1527 Mon Sep 17 00:00:00 2001 From: Mustafa Soylu Date: Wed, 14 Feb 2024 17:20:23 +0100 Subject: [PATCH 2/6] add fortran tests --- tests/conftest.py | 7 +++ tests/data/fpm.toml | 81 ++++++++++++++++++++++++++++ tests/input/test_fortran_validate.py | 27 ++++++++++ tests/output/test_fortran_writer.py | 60 +++++++++++++++++++++ 4 files changed, 175 insertions(+) create mode 100644 tests/data/fpm.toml create mode 100644 tests/input/test_fortran_validate.py create mode 100644 tests/output/test_fortran_writer.py diff --git a/tests/conftest.py b/tests/conftest.py index 5a60da05..65cb237d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,6 +10,7 @@ from somesy.package_json.writer import PackageJSON from somesy.pyproject import Pyproject from somesy.julia import Julia +from somesy.fortran import Fortran class FileTypes(Enum): @@ -19,6 +20,7 @@ class FileTypes(Enum): SOMESY = "somesy" PACKAGE_JSON = "package_json" JULIA = "julia" + FORTRAN = "fortran" @pytest.fixture(scope="session", autouse=True) @@ -72,6 +74,8 @@ def _create_files(files: Set[Tuple[FileTypes, str]]): read_file_name = read_file_path / Path("package.json") elif file_type == FileTypes.JULIA: read_file_name = read_file_path / Path("Project.toml") + elif file_type == FileTypes.FORTRAN: + read_file_name = read_file_path / Path("fpm.toml") with open(read_file_name, "r") as f: content = f.read() @@ -120,6 +124,9 @@ def _load_files(files: Set[FileTypes]): elif file_type == FileTypes.JULIA: read_file_name = read_file_name / Path("Project.toml") file_instances[file_type] = Julia(read_file_name) + elif file_type == FileTypes.FORTRAN: + read_file_name = read_file_name / Path("fpm.toml") + file_instances[file_type] = Fortran(read_file_name) return file_instances diff --git a/tests/data/fpm.toml b/tests/data/fpm.toml new file mode 100644 index 00000000..a61eed8f --- /dev/null +++ b/tests/data/fpm.toml @@ -0,0 +1,81 @@ +name = "test-package" +version = "0.1.0" +description = "This is a test package for demonstration purposes." +license = "MIT" +author = "John Doe " +copyright = "2020 John Doe" +categories = ["Command Line"] +keywords = ["test", "demo", "example"] +homepage = "https://example.com/test-package" + +# unit test program +test = [ + { name="test_func", source-dir="test", main="test_func.f90" } + ] + +[install] +library=true + +[library] +source-dir="src" + +# project metadata +[tool.somesy.project] +name = "testproject" +version = "1.0.0" +description = "This is a test project for demonstration purposes." +keywords = ["test", "demo", "example"] +license = "MIT" +repository = "https://github.com/example/testproject" +homepage = "https://example.com/testproject" + +[[tool.somesy.project.people]] +family-names = "Doe" +given-names = "John" +email = "john.doe@example.com" +orcid = "https://orcid.org/0000-0000-0000-0000" + +contribution = "The main developer, maintainer, and tester." +contribution_begin = "2023-01-15" +contribution_types = ["maintenance", "code", "test", "review", "doc"] + +author = true +maintainer = true +publication_author = true + +[[tool.somesy.project.people]] +family-names = "Doe" +given-names = "Jane" +email = "jane.doe@example.com" +orcid = "https://orcid.org/0000-0000-0000-0001" + +contribution = "Initial concepts, tool development and enhancement, documentation." +contribution_begin = "2023-02-20" +contribution_types = ["ideas", "code", "test", "review", "doc"] + +author = true + +[[tool.somesy.project.people]] +family-names = "Doe" +given-names = "Michael" +email = "michael.doe@example.com" +orcid = "https://orcid.org/0000-0000-0000-0002" + +contribution = "Valuable input concerning metadata standards and usability." +contribution_begin = "2023-03-10" +contribution_types = ["ideas"] +publication_author = true + +[tool.somesy.config] +no_sync_cff = false +cff_file = "CITATION.cff" +no_sync_pyproject = true +no_sync_codemeta = false +codemeta_file = "codemeta.json" +no_sync_package_json = true +no_sync_julia = true +no_sync_fortran = false +fortran_file = "fpm.toml" +show_info = false +verbose = false +debug = false diff --git a/tests/input/test_fortran_validate.py b/tests/input/test_fortran_validate.py new file mode 100644 index 00000000..e85ef897 --- /dev/null +++ b/tests/input/test_fortran_validate.py @@ -0,0 +1,27 @@ +import pytest +from tomlkit import dump + +from somesy.fortran import Fortran + + +def test_fortran_validate_accept(load_files, file_types): + """Validate by loading the data fpm.toml file using the fixture.""" + load_files([file_types.FORTRAN]) + + +def test_fortran_validate(tmp_path): + """Test validating a fpm.toml file.""" + + # create a fpm.toml file but with a invalid values + reject_fortran_object = { + "name": "12somesy", + "version": "abc", + "authors": ["John Doe <"], + } + + invalid_fortran_path = tmp_path / "fpm.toml" + with open(invalid_fortran_path, "w+") as f: + dump(reject_fortran_object, f) + + with pytest.raises(ValueError): + Fortran(invalid_fortran_path) diff --git a/tests/output/test_fortran_writer.py b/tests/output/test_fortran_writer.py new file mode 100644 index 00000000..858ff1a6 --- /dev/null +++ b/tests/output/test_fortran_writer.py @@ -0,0 +1,60 @@ +from pathlib import Path + +import pytest + +from somesy.core.models import LicenseEnum, Person, ProjectMetadata +from somesy.fortran.writer import Fortran + + +@pytest.fixture +def fortran(load_files, file_types): + files = load_files([file_types.FORTRAN]) + return files[file_types.FORTRAN] + + +@pytest.fixture +def fortran_file(create_files, file_types): + folder = create_files([(file_types.FORTRAN, "fpm.toml")]) + return folder / Path("fpm.toml") + + +def test_content_match(fortran): + assert fortran.name == "test-package" + assert len(fortran.authors) == 1 + + +def test_sync(fortran, somesy_input): + # with 'full name ' format + fortran.sync(somesy_input.project) + assert fortran.name == "testproject" + assert fortran.version == "1.0.0" + assert fortran.authors[0] == "John Doe " + + +def test_sync_free_text(fortran_file, somesy_input): + # update author to have a free text format + content = fortran_file.read_text() + content = content.replace( + 'author = "John Doe "', 'author = "John Doe"' + ) + + # write the new content + fortran_file.write_text(content) + + # read the file again + fortran = Fortran(fortran_file) + fortran.sync(somesy_input.project) + assert fortran.name == "testproject" + assert fortran.version == "1.0.0" + assert fortran.authors[0] == "John Doe " + + +def test_save(tmp_path, fortran): + custom_path = tmp_path / Path("fpm.toml") + fortran.save(custom_path) + assert custom_path.is_file() + custom_path.unlink() + + +def test_from_person(person): + assert Fortran._from_person(person) == f"{person.full_name} <{person.email}>" From c26131c2fcff5623328652373989856e6c74dfcd Mon Sep 17 00:00:00 2001 From: Mustafa Soylu Date: Wed, 14 Feb 2024 17:21:04 +0100 Subject: [PATCH 3/6] add fortran options to commands and cli --- src/somesy/cli/init.py | 7 +++++++ src/somesy/cli/sync.py | 34 +++++++++++++++++++++++++++++++--- src/somesy/commands/sync.py | 24 +++++++++++++++++++++++- src/somesy/core/core.py | 8 +++++--- src/somesy/core/models.py | 9 ++++++++- 5 files changed, 74 insertions(+), 8 deletions(-) diff --git a/src/somesy/cli/init.py b/src/somesy/cli/init.py index e3c693de..9020b912 100644 --- a/src/somesy/cli/init.py +++ b/src/somesy/cli/init.py @@ -63,6 +63,13 @@ def config(): if julia_file is not None or julia_file != "": options["julia_file"] = julia_file + options["no_sync_fortran"] = not typer.confirm( + "Do you want to sync to a fpm.toml(fortran) file?", default=True + ) + fortran_file = typer.prompt("fpm.toml(fortran) file path", default="fpm.toml") + if fortran_file is not None or fortran_file != "": + options["fortran_file"] = fortran_file + options["show_info"] = typer.confirm( "Do you want to show info about the sync process?" ) diff --git a/src/somesy/cli/sync.py b/src/somesy/cli/sync.py index c35e09d2..6623431d 100644 --- a/src/somesy/cli/sync.py +++ b/src/somesy/cli/sync.py @@ -104,13 +104,13 @@ def sync( no_sync_julia: bool = typer.Option( None, "--no-sync-julia", - "-M", - help="Do not sync Project.toml(Julia) file", + "-K", + help="Do not sync Project.toml(Julia) file (default: False)", ), julia_file: Path = typer.Option( None, "--julia-file", - "-m", + "-k", exists=True, file_okay=True, dir_okay=False, @@ -119,6 +119,24 @@ def sync( resolve_path=True, help="Custom Project.toml(Julia) file path", ), + no_sync_fortran: bool = typer.Option( + None, + "--no-sync-fortran", + "-F", + help="Do not sync fpm.toml(fortran) file (default: False)", + ), + fortran_file: Path = typer.Option( + None, + "--fortran-file", + "-f", + exists=True, + file_okay=True, + dir_okay=False, + writable=True, + readable=True, + resolve_path=True, + help="Custom fpm.toml(fortran) file path", + ), ): """Sync project metadata input with metadata files.""" somesy_input = resolved_somesy_input( @@ -133,6 +151,8 @@ def sync( codemeta_file=codemeta_file, no_sync_julia=no_sync_julia, julia_file=julia_file, + no_sync_fortran=no_sync_fortran, + fortran_file=fortran_file, ) run_sync(somesy_input) @@ -156,6 +176,14 @@ def run_sync(somesy_input: SomesyInput): logger.info( f" - [italic]codemeta.json[/italic]:\t[grey]{conf.codemeta_file}[/grey]\n" ) + if not conf.no_sync_julia: + logger.info( + f" - [italic]Project.toml(Julia)[/italic]:\t[grey]{conf.julia_file}[/grey]" + ) + if not conf.no_sync_fortran: + logger.info( + f" - [italic]fpm.toml(fortran)[/italic]:\t[grey]{conf.fortran_file}[/grey]" + ) # ---- sync_command(somesy_input) # ---- diff --git a/src/somesy/commands/sync.py b/src/somesy/commands/sync.py index 2c529813..bdc4804a 100644 --- a/src/somesy/commands/sync.py +++ b/src/somesy/commands/sync.py @@ -7,6 +7,7 @@ from somesy.cff.writer import CFF from somesy.codemeta import Codemeta from somesy.core.models import ProjectMetadata, SomesyInput +from somesy.fortran.writer import Fortran from somesy.julia.writer import Julia from somesy.package_json.writer import PackageJSON from somesy.pyproject.writer import Pyproject @@ -40,6 +41,9 @@ def sync(somesy_input: SomesyInput): if not conf.no_sync_julia: _sync_julia(metadata, conf.julia_file) + if not conf.no_sync_fortran: + _sync_fortran(metadata, conf.fortran_file) + def _sync_python( metadata: ProjectMetadata, @@ -120,7 +124,7 @@ def _sync_julia( """Sync Project.toml file using project metadata. Args: - metadata (ProjectMetadata): project metadata to sync pyproject.toml file. + metadata (ProjectMetadata): project metadata to sync Project.toml file. julia_file (Path, optional): Project.toml file path if wanted to be synced. Defaults to None. """ logger.verbose("Loading Project.toml file.") @@ -129,3 +133,21 @@ def _sync_julia( cm.sync(metadata) cm.save() logger.verbose(f"Saved synced Project.toml file to {julia_file}.") + + +def _sync_fortran( + metadata: ProjectMetadata, + fortran_file: Path, +): + """Sync fpm.toml file using project metadata. + + Args: + metadata (ProjectMetadata): project metadata to sync fpm.toml file. + fortran_file (Path, optional): fpm.toml file path if wanted to be synced. Defaults to None. + """ + logger.verbose("Loading fpm.toml file.") + cm = Fortran(fortran_file) + logger.verbose("Syncing fpm.toml file.") + cm.sync(metadata) + cm.save() + logger.verbose(f"Saved synced fpm.toml file to {fortran_file}.") diff --git a/src/somesy/core/core.py b/src/somesy/core/core.py index bf88524e..27149fda 100644 --- a/src/somesy/core/core.py +++ b/src/somesy/core/core.py @@ -14,6 +14,7 @@ "pyproject.toml", "package.json", "Project.toml", + "fpm.toml", ] """Input files ordered by priority for discovery.""" @@ -78,9 +79,10 @@ def get_input_content(path: Path, *, no_unwrap: bool = False) -> Dict[str, Any]: return ret if no_unwrap else ret.unwrap() # pyproject.toml - if ( - path.suffix == ".toml" and "pyproject" in path.name - ) or path.name == "Project.toml": + if (path.suffix == ".toml" and "pyproject" in path.name) or path.name in [ + "Project.toml", + "fpm.toml", + ]: with open(path, "r") as f: input_content = tomlkit.load(f) if "tool" in input_content and "somesy" in input_content["tool"]: diff --git a/src/somesy/core/models.py b/src/somesy/core/models.py index 87b6419e..3032f45d 100644 --- a/src/somesy/core/models.py +++ b/src/somesy/core/models.py @@ -119,7 +119,7 @@ def model_dump_json(self, *args, **kwargs): return json.dumps(ret, ensure_ascii=False) -_SOMESY_TARGETS = ["cff", "pyproject", "package_json", "codemeta", "julia"] +_SOMESY_TARGETS = ["cff", "pyproject", "package_json", "codemeta", "julia", "fortran"] class SomesyConfig(SomesyBaseModel): @@ -190,6 +190,13 @@ def at_least_one_target(cls, values): "Project.toml" ) + no_sync_fortran: Annotated[ + bool, Field(description="Do not sync with fpm.toml.") + ] = False + fortran_file: Annotated[Path, Field(description="fpm.toml file path.")] = Path( + "fpm.toml" + ) + def log_level(self) -> SomesyLogLevel: """Return log level derived from this configuration.""" return SomesyLogLevel.from_flags( From 0b78fa293a2899c593162245b3aeb267beb121f6 Mon Sep 17 00:00:00 2001 From: Mustafa Soylu Date: Wed, 14 Feb 2024 17:21:33 +0100 Subject: [PATCH 4/6] update somesy config --- .somesy.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/.somesy.toml b/.somesy.toml index e744b0bb..28184184 100644 --- a/.somesy.toml +++ b/.somesy.toml @@ -76,6 +76,7 @@ no_sync_codemeta = false codemeta_file = "codemeta.json" no_sync_package_json = true no_sync_julia = true +no_sync_fortran = true show_info = false verbose = false debug = true From 1d14fce1ed5880f274f79cbd3f34d3d5b9134f18 Mon Sep 17 00:00:00 2001 From: Mustafa Soylu Date: Thu, 15 Feb 2024 10:05:12 +0100 Subject: [PATCH 5/6] update docs --- CHANGELOG.md | 1 + README.md | 14 ++++---- docs/manual.md | 87 ++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 72 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9784635d..0a6a48b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Please consult the changelog to inform yourself about breaking changes and secur * added separate `documentation` URL to Project metadata model * added support for Julia `Project.toml` file +* added support for fortran `fpm.toml` file ## [v0.3.1](https://github.com/Materials-Data-Science-and-Informatics/somesy/tree/v0.3.1) (2024-01-23) { id="0.3.1" } diff --git a/README.md b/README.md index 08fbe210..66d3363f 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ verbose = true # show detailed information about what somesy is doing Alternatively, you can also add the somesy configuration to an existing -`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. +`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. ### Using somesy @@ -125,7 +125,7 @@ authoritative** source for project metadata, which is used to update all supported (and enabled) *target files*. You can find an overview of supported formats further below. -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. +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. You can see call available options with `somesy --help`, 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. | -------------- | ------ |-| ----------------------------- | ------ | | (.)somesy.toml | ✓ | | pyproject.toml _(poetry)_ | ✓ | | pyproject.toml | ✓ | | pyproject.toml _(setuptools)_ | ✓(1.) | -| package.json | ✓ | | package.json | ✓(2.) | -| Project.toml | ✓ | | Project.toml | ✓ | +| package.json | ✓ | | package.json _(JavaScript)_ | ✓(2.) | +| Project.toml | ✓ | | Project.toml _(Julia)_ | ✓ | +| fpm.toml | ✓ | | fpm.toml _(Fortran)_ | ✓(3.) | | | | | CITATION.cff | ✓ | -| | | | codemeta.json | ✓(3.) | +| | | | codemeta.json | ✓(4.) | **Notes:** 1. note that `somesy` does not support setuptools *dynamic fields* 2. `package.json` only supports one author, so `somesy` will pick the *first* listed author -3. unlike other targets, `somesy` will *re-create* the `codemeta.json` (i.e. do not edit it by hand!) +3. `fpm.toml` only supports one author and maintainer, so `somesy` will pick the *first* listed author and maintainer +4. unlike other targets, `somesy` will *re-create* the `codemeta.json` (i.e. do not edit it by hand!) diff --git a/docs/manual.md b/docs/manual.md index f5917bf8..ed2f29be 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -117,33 +117,33 @@ some of the currently supported formats. Bold field names are mandatory, the oth === "Person Metadata" - | Somesy Field | Poetry Config | SetupTools Config | Julia Config | package.json | CITATION.cff | CodeMeta | - | ---------------- | ------------- | ----------------- | ------------ | ------------ | --------------- | --------------- | - | | | | | | | | - | **given-names** | name+email | name | name+email | name | given-names | givenName | - | **family-names** | name+email | name | name+email | name | family-names | familyName | - | **email** | name+email | email | name+email | email | email | email | - | orcid | - | - | - | url | orcid | id | - | *(many others)* | - | - | - | - | *(same)* | *(same)* | + | Somesy Field | Poetry Config | SetupTools Config | Julia Config | Fortran Config | package.json | CITATION.cff | CodeMeta | + | ---------------- | ------------- | ----------------- | ------------ | -------------- | ------------ | --------------- | --------------- | + | | | | | | | | | + | **given-names** | name+email | name | name+email | name+email | name | given-names | givenName | + | **family-names** | name+email | name | name+email | name+email | name | family-names | familyName | + | **email** | name+email | email | name+email | name+email | email | email | email | + | orcid | - | - | - | - | url | orcid | id | + | *(many others)* | - | - | - | - | - | *(same)* | *(same)* | === "Project Metadata" - | Somesy Field | Poetry Config | SetupTools Config | Julia Config | package.json | CITATION.cff | CodeMeta | - | ----------------- | ------------- | ------------------ | ------------ | ------------ | --------------- | ----------------- | - | | | | | | | - | **name** | name | name | name | name | title | name | - | **description** | description | description | - | description | abstract | description | - | **license** | license | license | - | license | license | license | - | **version** | version | version | version | version | version | version | - | | | | | | | | - | ***author=true*** | authors | authors | authors | author | authors | author | - | *maintainer=true* | maintainers | maintainers | - | maintainers | contact | maintainer | - | *people* | - | - | - | contributors | - | contributor | - | | | | | | | | - | keywords | keywords | keywords | - | keywords | keywords | keywords | - | homepage | homepage | urls.homepage | - | homepage | url | url | - | repository | repository | urls.repository | - | repository | repository_code | codeRepository | - | documentation | documentation | urls.documentation | - | - | - | buildInstructions | + | Somesy Field | Poetry Config | SetupTools Config | Julia Config | Fortran Config | package.json | CITATION.cff | CodeMeta | + | ----------------- | ------------- | ------------------ | ------------ | -------------- | ------------ | --------------- | ----------------- | + | | | | | | | | + | **name** | name | name | name | name | name | title | name | + | **description** | description | description | - | description | description | abstract | description | + | **license** | license | license | - | license | license | license | license | + | **version** | version | version | version | version | version | version | version | + | | | | | | | | | + | ***author=true*** | authors | authors | authors | author | author | authors | author | + | *maintainer=true* | maintainers | maintainers | - | maintainer | maintainers | contact | maintainer | + | *people* | - | - | - | - | contributors | - | contributor | + | | | | | | | | | + | keywords | keywords | keywords | - | keywords | keywords | keywords | keywords | + | homepage | homepage | urls.homepage | - | homepage | homepage | url | url | + | repository | repository | urls.repository | - | - | repository | repository_code | codeRepository | + | documentation | documentation | urls.documentation | - | - | - | - | buildInstructions | Note that the mapping is often not 1-to-1. For example, CITATION.cff allows rich 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 * `somesy.toml` * `pyproject.toml` (in `tool.somesy` section) * `Project.toml` (in `tool.somesy` section) +* `fpm.toml` (in `tool.somesy` section) * `package.json` (in `somesy` section) which is located in the current working directory. If you want to provide @@ -260,6 +261,40 @@ one of the supported input formats: verbose = true # show detailed information about what somesy is doing ``` +=== "fpm.toml" + ```toml + name = "my-amazing-project" + version = "0.1.0" + + [tool.somesy.project] + name = "my-amazing-project" + version = "0.1.0" + description = "Brief description of my amazing software." + + keywords = ["some", "descriptive", "keywords"] + license = "MIT" + repository = "https://github.com/username/my-amazing-project" + + # This is you, the proud author of your project + [[tool.somesy.project.people]] + given-names = "Jane" + family-names = "Doe" + email = "j.doe@example.com" + orcid = "https://orcid.org/0000-0000-0000-0001" + author = true # is a full author of the project (i.e. appears in citations) + maintainer = true # currently maintains the project (i.e. is a contact person) + + # this person is a acknowledged contributor, but not author or maintainer: + [[tool.somesy.project.people]] + given-names = "Another" + family-names = "Contributor" + email = "a.contributor@example.com" + orcid = "https://orcid.org/0000-0000-0000-0002" + + [tool.somesy.config] + verbose = true # show detailed information about what somesy is doing + ``` + === "package.json" ```json @@ -412,6 +447,10 @@ Therefore, **in such a case you will need to fix the ORCID in all configured som before running somesy (so somesy will not create new person entries), or after running somesy (to remove the duplicate entries with the incorrect ORCID). +!!! warning + + Person identification and merging is not applied to standards with free text fields for authors or maintainers, such as `fpm.toml`. + ### Codemeta While `somesy` is modifying existing files for most supported formats and implements From bc5c5a3effbfac359d18915fb1f05ac45e991ea5 Mon Sep 17 00:00:00 2001 From: Mustafa SOYLU Date: Fri, 16 Feb 2024 15:17:24 +0100 Subject: [PATCH 6/6] change julia flags to l --- src/somesy/cli/sync.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/somesy/cli/sync.py b/src/somesy/cli/sync.py index 6623431d..67b127ad 100644 --- a/src/somesy/cli/sync.py +++ b/src/somesy/cli/sync.py @@ -104,13 +104,13 @@ def sync( no_sync_julia: bool = typer.Option( None, "--no-sync-julia", - "-K", + "-L", help="Do not sync Project.toml(Julia) file (default: False)", ), julia_file: Path = typer.Option( None, "--julia-file", - "-k", + "-l", exists=True, file_okay=True, dir_okay=False,