diff --git a/pyproject_metadata/__init__.py b/pyproject_metadata/__init__.py index b3a4ee7..f654463 100644 --- a/pyproject_metadata/__init__.py +++ b/pyproject_metadata/__init__.py @@ -196,7 +196,6 @@ class StandardMetadata: def __post_init__(self) -> None: self.name = re.sub(r'[-_.]+', '-', self.name).lower() - self._update_dynamic(self.version) @classmethod def from_pyproject( @@ -226,6 +225,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') @@ -234,7 +237,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), @@ -255,8 +258,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 2cd3367..eb8aac1 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")'), @@ -220,6 +246,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 +255,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' dependencies = [ 99, ] @@ -238,6 +266,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' dependencies = [ 'definitely not a valid PEP 508 requirement!', ] @@ -252,6 +281,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' optional-dependencies = true '''), ( @@ -263,6 +293,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' [project.optional-dependencies] test = 'some string!' '''), @@ -275,6 +306,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' [project.optional-dependencies] test = [ true, @@ -289,6 +321,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' [project.optional-dependencies] test = [ 'definitely not a valid PEP 508 requirement!', @@ -304,6 +337,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 +347,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 +356,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' keywords = [ true, ] @@ -332,6 +368,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' authors = {} '''), ( @@ -343,6 +380,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' authors = [ true, ] @@ -357,6 +395,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' maintainers = {} '''), ( @@ -368,6 +407,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' maintainers = [ 10 ] @@ -382,6 +422,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 +431,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' classifiers = [ true, ] @@ -401,6 +443,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' [project.urls] homepage = true '''), @@ -411,6 +454,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' [project.urls] documentation = true '''), @@ -421,6 +465,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' [project.urls] repository = true '''), @@ -431,6 +476,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' [project.urls] changelog = true '''), @@ -441,6 +487,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 +497,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 +507,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' entry-points = [] '''), ( @@ -470,6 +519,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' entry-points = { section = 'something' } '''), ( @@ -481,6 +531,7 @@ textwrap.dedent(''' [project] name = 'test' + version = '0.1.0' [project.entry-points.section] entrypoint = [] '''), @@ -693,6 +744,7 @@ def test_requires_python(value): pyproject_metadata.StandardMetadata.from_pyproject({ 'project': { 'name': 'example', + 'version': '0.1.0', 'requires-python': value, }, }) @@ -709,5 +761,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