From 581a309c2acae4890104dd6ba05d9b578576e4e7 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 3 Nov 2023 17:19:02 -0400 Subject: [PATCH] fix: require version in dynamic if unset Signed-off-by: Henry Schreiner --- pyproject_metadata/__init__.py | 11 +++---- tests/test_standard_metadata.py | 55 +++++++++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/pyproject_metadata/__init__.py b/pyproject_metadata/__init__.py index cc8fc68..70e33a7 100644 --- a/pyproject_metadata/__init__.py +++ b/pyproject_metadata/__init__.py @@ -194,9 +194,6 @@ class StandardMetadata: gui_scripts: dict[str, str] = dataclasses.field(default_factory=dict) dynamic: list[str] = dataclasses.field(default_factory=list) - def __post_init__(self) -> None: - self._update_dynamic(self.version) - @property def canonical_name(self) -> str: return packaging.utils.canonicalize_name(self.name) @@ -229,6 +226,10 @@ def from_pyproject( version_string = fetcher.get_str('project.version') requires_python_string = fetcher.get_str('project.requires-python') + version = packaging.version.Version(version_string) if version_string else None + + if version is None and 'version' not in dynamic: + raise ConfigurationError('Field "project.version" missing and "version" not specified in "project.dynamic"') # Description can't be multiline description = fetcher.get_str('project.description') @@ -237,7 +238,7 @@ def from_pyproject( return cls( name, - packaging.version.Version(version_string) if version_string else None, + version, description, cls._get_license(fetcher, project_dir), cls._get_readme(fetcher, project_dir), @@ -258,8 +259,6 @@ def from_pyproject( def _update_dynamic(self, value: Any) -> None: if value and 'version' in self.dynamic: self.dynamic.remove('version') - elif not value and 'version' not in self.dynamic: - self.dynamic.append('version') def __setattr__(self, name: str, value: Any) -> None: # update dynamic when version is set diff --git a/tests/test_standard_metadata.py b/tests/test_standard_metadata.py index 14e823e..edf9d29 100644 --- a/tests/test_standard_metadata.py +++ b/tests/test_standard_metadata.py @@ -29,6 +29,7 @@ textwrap.dedent(''' [project] name = true + version = '0.1.0' '''), ('Field "project.name" has an invalid type, expecting a string (got "True")'), ), @@ -37,6 +38,7 @@ textwrap.dedent(''' [project] name = true + version = '0.1.0' dynamic = [ 'name', ] @@ -52,11 +54,19 @@ '''), ('Field "project.version" has an invalid type, expecting a string (got "True")'), ), + ( + textwrap.dedent(''' + [project] + name = 'test' + '''), + ('Field "project.version" missing and "version" not specified in "project.dynamic"'), + ), # license ( textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' license = true '''), ('Field "project.license" has an invalid type, expecting a dictionary of strings (got "True")'), @@ -65,6 +75,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' license = {} '''), ('Invalid "project.license" value, expecting either "file" or "text" (got "{}")'), @@ -73,6 +84,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' license = { file = '...', text = '...' } '''), ( @@ -84,6 +96,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' license = { made-up = ':(' } '''), ( @@ -94,6 +107,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' license = { file = true } '''), ('Field "project.license.file" has an invalid type, expecting a string (got "True")'), @@ -102,6 +116,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' license = { text = true } '''), ('Field "project.license.text" has an invalid type, expecting a string (got "True")'), @@ -110,6 +125,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' license = { file = 'this-file-does-not-exist' } '''), ('License file not found ("this-file-does-not-exist")'), @@ -119,6 +135,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' readme = true '''), ( @@ -130,6 +147,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' readme = {} '''), ( @@ -140,6 +158,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' readme = { file = '...', text = '...' } '''), ( @@ -151,6 +170,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' readme = { made-up = ':(' } '''), ( @@ -161,6 +181,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' readme = { file = true } '''), ('Field "project.readme.file" has an invalid type, expecting a string (got "True")'), @@ -169,6 +190,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' readme = { text = true } '''), ('Field "project.readme.text" has an invalid type, expecting a string (got "True")'), @@ -177,6 +199,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' readme = { file = 'this-file-does-not-exist', content-type = '...' } '''), ('Readme file not found ("this-file-does-not-exist")'), @@ -185,6 +208,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' readme = { file = 'README.md' } '''), ('Field "project.readme.content-type" missing'), @@ -193,6 +217,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' readme = { text = '...' } '''), ('Field "project.readme.content-type" missing'), @@ -202,6 +227,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' description = true '''), ('Field "project.description" has an invalid type, expecting a string (got "True")'), @@ -210,6 +236,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' description = """Multiple lines.""" '''), @@ -220,6 +247,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' dependencies = 'some string!' '''), ('Field "project.dependencies" has an invalid type, expecting a list of strings (got "some string!")'), @@ -228,6 +256,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' dependencies = [ 99, ] @@ -238,6 +267,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' dependencies = [ 'definitely not a valid PEP 508 requirement!', ] @@ -252,6 +282,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' optional-dependencies = true '''), ( @@ -263,6 +294,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' [project.optional-dependencies] test = 'some string!' '''), @@ -275,6 +307,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' [project.optional-dependencies] test = [ true, @@ -289,6 +322,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' [project.optional-dependencies] test = [ 'definitely not a valid PEP 508 requirement!', @@ -304,6 +338,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' requires-python = true '''), ('Field "project.requires-python" has an invalid type, expecting a string (got "True")'), @@ -313,6 +348,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' keywords = 'some string!' '''), ('Field "project.keywords" has an invalid type, expecting a list of strings (got "some string!")'), @@ -321,6 +357,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' keywords = [ true, ] @@ -332,6 +369,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' authors = {} '''), ( @@ -343,6 +381,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' authors = [ true, ] @@ -357,6 +396,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' maintainers = {} '''), ( @@ -368,6 +408,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' maintainers = [ 10 ] @@ -382,6 +423,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' classifiers = 'some string!' '''), ('Field "project.classifiers" has an invalid type, expecting a list of strings (got "some string!")'), @@ -390,6 +432,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' classifiers = [ true, ] @@ -401,6 +444,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' [project.urls] homepage = true '''), @@ -411,6 +455,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' [project.urls] documentation = true '''), @@ -421,6 +466,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' [project.urls] repository = true '''), @@ -431,6 +477,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' [project.urls] changelog = true '''), @@ -441,6 +488,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' scripts = [] '''), ('Field "project.scripts" has an invalid type, expecting a dictionary of strings (got "[]")'), @@ -450,6 +498,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' gui-scripts = [] '''), ('Field "project.gui-scripts" has an invalid type, expecting a dictionary of strings (got "[]")'), @@ -459,6 +508,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' entry-points = [] '''), ( @@ -470,6 +520,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' entry-points = { section = 'something' } '''), ( @@ -481,6 +532,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' [project.entry-points.section] entrypoint = [] '''), @@ -694,6 +746,7 @@ def test_requires_python(value): pyproject_metadata.StandardMetadata.from_pyproject({ 'project': { 'name': 'example', + 'version': '0.1.0', 'requires-python': value, }, }) @@ -710,5 +763,3 @@ def test_version_dynamic(): }) metadata.version = packaging.version.Version('1.2.3') assert 'version' not in metadata.dynamic - metadata.version = None - assert 'version' in metadata.dynamic