Coverage for src/somesy/package_json/writer.py: 98%
64 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-08-10 14:33 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-08-10 14:33 +0000
1"""package.json parser and saver."""
2import json
3import logging
4from collections import OrderedDict
5from pathlib import Path
6from typing import List, Optional
8from rich.pretty import pretty_repr
10from somesy.core.models import Person, ProjectMetadata
11from somesy.core.writer import ProjectMetadataWriter
12from somesy.package_json.models import PackageJsonConfig
14logger = logging.getLogger("somesy")
17class PackageJSON(ProjectMetadataWriter):
18 """package.json parser and saver."""
20 def __init__(
21 self,
22 path: Path,
23 ):
24 """package.json parser.
26 See [somesy.core.writer.ProjectMetadataWriter.__init__][].
27 """
28 mappings = {
29 "authors": ["author"],
30 }
31 super().__init__(path, create_if_not_exists=False, direct_mappings=mappings)
33 @property
34 def authors(self):
35 """Return the only author of the package.json file as list."""
36 return [self._get_property(self._get_key("authors"))]
38 @authors.setter
39 def authors(self, authors: List[Person]) -> None:
40 """Set the authors of the project."""
41 authors = self._from_person(authors[0])
42 self._set_property(self._get_key("authors"), authors)
44 @property
45 def contributors(self):
46 """Return the contributors of the package.json file."""
47 return self._get_property(self._get_key("contributors"))
49 @contributors.setter
50 def contributors(self, contributors: List[Person]) -> None:
51 """Set the contributors of the project."""
52 contributors = [self._from_person(c) for c in contributors]
53 self._set_property(self._get_key("contributors"), contributors)
55 def _load(self) -> None:
56 """Load package.json file."""
57 with self.path.open() as f:
58 self._data = json.load(f, object_pairs_hook=OrderedDict)
60 def _validate(self) -> None:
61 """Validate package.json content using pydantic class."""
62 config = dict(self._get_property([]))
63 logger.debug(
64 f"Validating config using {PackageJsonConfig.__name__}: {pretty_repr(config)}"
65 )
66 PackageJsonConfig(**config)
68 def save(self, path: Optional[Path] = None) -> None:
69 """Save the package.json file."""
70 path = path or self.path
71 logger.debug(f"Saving package.json to {path}")
73 with path.open("w") as f:
74 # package.json indentation is 2 spaces
75 json.dump(self._data, f, indent=2)
77 @staticmethod
78 def _from_person(person: Person):
79 """Convert project metadata person object to package.json dict for person format."""
80 person_dict = {"name": person.full_name}
81 if person.email:
82 person_dict["email"] = person.email
83 if person.orcid:
84 person_dict["url"] = person.orcid
85 return person_dict
87 @staticmethod
88 def _to_person(person) -> Person:
89 """Convert package.json dict or str for person format to project metadata person object."""
90 if isinstance(person, str):
91 # parse from package.json format
92 person = PackageJsonConfig.convert_author(person).dict(exclude_none=True)
94 names = list(map(lambda s: s.strip(), person["name"].split()))
95 person_obj = {
96 "given-names": " ".join(names[:-1]),
97 "family-names": names[-1],
98 }
99 if "email" in person:
100 person_obj["email"] = person["email"].strip()
101 if "url" in person:
102 person_obj["orcid"] = person["url"].strip()
103 return Person(**person_obj)
105 def sync(self, metadata: ProjectMetadata) -> None:
106 """Sync package.json with project metadata.
108 Use existing sync function from ProjectMetadataWriter but update repository and contributors.
109 """
110 super().sync(metadata)
111 self.contributors = self._sync_person_list(self.contributors, metadata.people)
112 if metadata.repository:
113 self.repository = {"type": "git", "url": metadata.repository}