Coverage for src/somesy/fortran/writer.py: 91%
67 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-11-03 13:31 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-11-03 13:31 +0000
1"""Fortran writer."""
3import logging
4from pathlib import Path
6import tomlkit
7from rich.pretty import pretty_repr
9from somesy.core.models import Entity, Person, ProjectMetadata, parse_name_email
10from somesy.core.writer import (
11 FieldKeyMapping,
12 IgnoreKey,
13 ProjectMetadataWriter,
14 format_toml_data,
15 license_expression,
16)
18from .models import FortranConfig
20logger = logging.getLogger("somesy")
23class Fortran(ProjectMetadataWriter):
24 """Fortran config file handler parsed from fpm.toml."""
26 def __init__(
27 self,
28 path: Path,
29 pass_validation: bool | None = False,
30 ):
31 """Fortran config file handler parsed from fpm.toml.
33 See [somesy.core.writer.ProjectMetadataWriter.__init__][].
34 """
35 mappings: FieldKeyMapping = {
36 "authors": ["author"],
37 "maintainers": ["maintainer"],
38 "documentation": IgnoreKey(),
39 }
40 super().__init__(
41 path,
42 create_if_not_exists=False,
43 direct_mappings=mappings,
44 pass_validation=pass_validation,
45 )
47 @property
48 def authors(self):
49 """Return the only author of the fpm.toml file as list."""
50 author = self._get_property(self._get_key("authors"))
51 return [author] if author else []
53 @authors.setter
54 def authors(self, authors: list[Person | Entity]) -> None:
55 """Set the authors of the project."""
56 self._set_property(self._get_key("authors"), self._from_person(authors[0]))
58 @property
59 def maintainers(self):
60 """Return the only author of the fpm.toml file as list."""
61 maintainers = self._get_property(self._get_key("maintainers"))
62 if maintainers:
63 return [self._get_property(self._get_key("maintainers"))]
64 return []
66 @maintainers.setter
67 def maintainers(self, maintainers: list[Person | Entity]) -> None:
68 """Set the maintainers of the project."""
69 maintainer = self._from_person(maintainers[0])
70 self._set_property(self._get_key("maintainers"), maintainer)
72 def _load(self) -> None:
73 """Load fpm.toml file."""
74 with open(self.path, encoding="utf-8") as f:
75 self._data = tomlkit.load(f)
77 def _validate(self) -> None:
78 """Validate poetry config using pydantic class.
80 In order to preserve toml comments and structure, tomlkit library is used.
81 Pydantic class only used for validation.
82 """
83 if self.pass_validation:
84 return
85 config = dict(self._get_property([]))
86 logger.debug(
87 f"Validating config using {FortranConfig.__name__}: {pretty_repr(config)}"
88 )
89 FortranConfig(**config)
91 def save(self, path: Path | None = None) -> None:
92 """Save the fpm file."""
93 path = path or self.path
94 format_toml_data(self._data)
96 with open(path, "w", encoding="utf-8") as f:
97 tomlkit.dump(self._data, f)
99 @staticmethod
100 def _from_person(person: Person | Entity):
101 """Convert project metadata person/entity object to poetry string for person format "full name <email>."""
102 return person.to_name_email_string()
104 @staticmethod
105 def _to_person(person_obj: str) -> Person | Entity | None:
106 """Convert from free string to person or entity object."""
107 return parse_name_email(person_obj)
109 def sync(self, metadata: ProjectMetadata) -> None:
110 """Sync output file with other metadata files."""
111 if metadata.name is not None:
112 self.name = metadata.name
113 if metadata.description is not None:
114 self.description = metadata.description
116 if metadata.version:
117 self.version = metadata.version
119 if metadata.keywords:
120 self.keywords = metadata.keywords
122 if metadata.authors():
123 self.authors = metadata.authors()
124 maintainers = metadata.maintainers()
126 # set if not empty
127 if maintainers:
128 # only one maintainer is allowed
129 self.maintainers = maintainers
131 if licenses := metadata.license:
132 self.license = license_expression(licenses)
134 if metadata.homepage:
135 self.homepage = str(metadata.homepage)