Skip to content

Commit 893f1bc

Browse files
bjoernricksgreenbonebot
authored andcommitted
Add: Support standard project.version field in pyproject.toml
Since we started pontos the fields in pyproject.toml got more and more standardized. Nowadays the version information can be found at the `project.version` field. For example ```toml [project] version = "1.2.3" ``` This change considers this version field now and also falls back to `tools.poetry.version` if it is not available. It also fixes release issues with other tools then poetry.
1 parent 30bf001 commit 893f1bc

File tree

2 files changed

+171
-18
lines changed

2 files changed

+171
-18
lines changed

pontos/version/commands/_python.py

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ def _get_version_from_pyproject_toml(self) -> Version:
3333
pyproject.toml file. The version may be in non standardized form.
3434
"""
3535

36+
if (
37+
"project" in self.pyproject_toml
38+
and "version" in self.pyproject_toml["project"] # type: ignore[operator]
39+
):
40+
return PEP440VersioningScheme.parse_version(
41+
str(self.pyproject_toml["project"]["version"]) # type: ignore[operator, index]
42+
)
43+
3644
if (
3745
"tool" in self.pyproject_toml
3846
and "poetry" in self.pyproject_toml["tool"] # type: ignore[operator] # noqa: E501
@@ -43,8 +51,7 @@ def _get_version_from_pyproject_toml(self) -> Version:
4351
)
4452

4553
raise VersionError(
46-
"Version information not found in "
47-
f"{self.project_file_path} file."
54+
f"Version information not found in {self.project_file_path} file."
4855
)
4956

5057
def _update_version_file(self, new_version: Version) -> None:
@@ -66,16 +73,23 @@ def _update_pyproject_version(
6673
self.project_file_path.read_text(encoding="utf-8")
6774
)
6875

69-
if "tool" not in pyproject_toml:
70-
tool_table = tomlkit.table()
71-
pyproject_toml["tool"] = tool_table
76+
poetry_lock_file_path = self.project_file_path.parent / "poetry.lock"
77+
if poetry_lock_file_path.exists():
78+
if "tool" not in pyproject_toml:
79+
tool_table = tomlkit.table()
80+
pyproject_toml["tool"] = tool_table
81+
82+
if "poetry" not in pyproject_toml["tool"]: # type: ignore
83+
poetry_table = tomlkit.table()
84+
pyproject_toml["tool"].add("poetry", poetry_table) # type: ignore
7285

73-
if "poetry" not in pyproject_toml["tool"]: # type: ignore
74-
poetry_table = tomlkit.table()
75-
# pylint: disable=line-too-long, no-member # ignore pylint (2.13.9) error: pontos/version/python.py:128:12: E1101: Instance of 'OutOfOrderTableProxy' has no 'add' member (no-member) # noqa: E501
76-
pyproject_toml["tool"].add("poetry", poetry_table) # type: ignore
86+
pyproject_toml["tool"]["poetry"]["version"] = str(new_version) # type: ignore
87+
else:
88+
if "project" not in pyproject_toml:
89+
project_table = tomlkit.table()
90+
pyproject_toml["project"] = project_table
7791

78-
pyproject_toml["tool"]["poetry"]["version"] = str(new_version) # type: ignore # pylint: disable=line-too-long # noqa: E501
92+
pyproject_toml["project"]["version"] = str(new_version) # type: ignore
7993

8094
self.project_file_path.write_text(
8195
tomlkit.dumps(pyproject_toml), encoding="utf-8"

tests/version/commands/test_python.py

Lines changed: 147 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ def test_empty_tool_section(self):
177177
def test_empty_tool_poetry_section(self):
178178
content = "__version__ = '22.1'"
179179
with temp_python_module(content, name="foo", change_into=True) as temp:
180+
temp_poetry_lock = temp.parent / "poetry.lock"
181+
temp_poetry_lock.touch()
180182
tmp_file = temp.parent / "pyproject.toml"
181183
tmp_file.write_text(
182184
"[tool.poetry]\n"
@@ -200,12 +202,38 @@ def test_empty_tool_poetry_section(self):
200202

201203
self.assertEqual(toml["tool"]["poetry"]["version"], "22.2")
202204

205+
def test_empty_project_section(self):
206+
content = "__version__ = '22.1'"
207+
with temp_python_module(content, name="foo", change_into=True) as temp:
208+
tmp_file = temp.parent / "pyproject.toml"
209+
tmp_file.write_text(
210+
"[project]\n"
211+
'[tool.pontos.version]\nversion-module-file = "foo.py"',
212+
encoding="utf8",
213+
)
214+
cmd = PythonVersionCommand(PEP440VersioningScheme)
215+
new_version = PEP440VersioningScheme.parse_version("22.2")
216+
previous_version = PEP440VersioningScheme.parse_version("22.1")
217+
updated = cmd.update_version(new_version)
218+
219+
self.assertEqual(updated.new, new_version)
220+
self.assertEqual(updated.previous, previous_version)
221+
self.assertEqual(
222+
updated.changed_files, [Path("foo.py"), tmp_file.resolve()]
223+
)
224+
225+
text = tmp_file.read_text(encoding="utf8")
226+
227+
toml = tomlkit.parse(text)
228+
229+
self.assertEqual(toml["project"]["version"], "22.2")
230+
203231
def test_override_existing_version(self):
204232
content = "__version__ = '1.2.3'"
205233
with temp_python_module(content, name="foo", change_into=True) as temp:
206234
tmp_file = temp.parent / "pyproject.toml"
207235
tmp_file.write_text(
208-
'[tool.poetry]\nversion = "1.2.3"\n'
236+
'[project]\nversion = "1.2.3"\n'
209237
'[tool.pontos.version]\nversion-module-file = "foo.py"',
210238
encoding="utf8",
211239
)
@@ -224,14 +252,14 @@ def test_override_existing_version(self):
224252

225253
toml = tomlkit.parse(text)
226254

227-
self.assertEqual(toml["tool"]["poetry"]["version"], "22.2")
255+
self.assertEqual(toml["project"]["version"], "22.2")
228256

229257
def test_development_version(self):
230258
content = "__version__ = '1.2.3'"
231259
with temp_python_module(content, name="foo", change_into=True) as temp:
232260
tmp_file = temp.parent / "pyproject.toml"
233261
tmp_file.write_text(
234-
'[tool.poetry]\nversion = "1.2.3"\n'
262+
'[project]\nversion = "1.2.3"\n'
235263
'[tool.pontos.version]\nversion-module-file = "foo.py"',
236264
encoding="utf8",
237265
)
@@ -250,7 +278,7 @@ def test_development_version(self):
250278

251279
toml = tomlkit.parse(text)
252280

253-
self.assertEqual(toml["tool"]["poetry"]["version"], "22.2.dev1")
281+
self.assertEqual(toml["project"]["version"], "22.2.dev1")
254282

255283
def test_no_update(self):
256284
content = "__version__ = '1.2.3'"
@@ -320,7 +348,32 @@ def test_current_version_not_equal_pyproject_toml_version(self):
320348
version = PEP440VersioningScheme.parse_version("1.2.3")
321349
cmd.verify_version(version)
322350

323-
def test_current_version(self):
351+
def test_current_version_with_project_version(self):
352+
fake_version_py = Path("foo.py")
353+
content = (
354+
'[project]\nversion = "1.2.3"\n'
355+
'[tool.pontos.version]\nversion-module-file = "foo.py"'
356+
)
357+
358+
with (
359+
temp_file(content, name="pyproject.toml", change_into=True),
360+
patch.object(
361+
PythonVersionCommand,
362+
"get_current_version",
363+
MagicMock(
364+
return_value=PEP440VersioningScheme.parse_version("1.2.3")
365+
),
366+
),
367+
patch.object(
368+
PythonVersionCommand,
369+
"version_file_path",
370+
new=PropertyMock(return_value=fake_version_py),
371+
),
372+
):
373+
cmd = PythonVersionCommand(PEP440VersioningScheme)
374+
cmd.verify_version("current")
375+
376+
def test_current_version_with_poetry_version(self):
324377
fake_version_py = Path("foo.py")
325378
content = (
326379
'[tool.poetry]\nversion = "1.2.3"\n'
@@ -345,7 +398,36 @@ def test_current_version(self):
345398
cmd = PythonVersionCommand(PEP440VersioningScheme)
346399
cmd.verify_version("current")
347400

348-
def test_current_failure(self):
401+
def test_current_failure_with_project_version(self):
402+
fake_version_py = Path("foo.py")
403+
content = (
404+
'[project]\nversion = "1.2.4"\n'
405+
'[tool.pontos.version]\nversion-module-file = "foo.py"'
406+
)
407+
408+
with (
409+
temp_file(content, name="pyproject.toml", change_into=True),
410+
patch.object(
411+
PythonVersionCommand,
412+
"get_current_version",
413+
MagicMock(
414+
return_value=PEP440VersioningScheme.parse_version("1.2.3")
415+
),
416+
),
417+
patch.object(
418+
PythonVersionCommand,
419+
"version_file_path",
420+
new=PropertyMock(return_value=fake_version_py),
421+
),
422+
self.assertRaisesRegex(
423+
VersionError,
424+
"The version .* in .* doesn't match the current version .*.",
425+
),
426+
):
427+
cmd = PythonVersionCommand(PEP440VersioningScheme)
428+
cmd.verify_version("current")
429+
430+
def test_current_failure_with_poetry_version(self):
349431
fake_version_py = Path("foo.py")
350432
content = (
351433
'[tool.poetry]\nversion = "1.2.4"\n'
@@ -374,7 +456,37 @@ def test_current_failure(self):
374456
cmd = PythonVersionCommand(PEP440VersioningScheme)
375457
cmd.verify_version("current")
376458

377-
def test_provided_version_mismatch(self):
459+
def test_provided_version_mismatch_with_project_version(self):
460+
fake_version_py = Path("foo.py")
461+
content = (
462+
'[project]\nversion = "1.2.3"\n'
463+
'[tool.pontos.version]\nversion-module-file = "foo.py"'
464+
)
465+
466+
with (
467+
temp_file(content, name="pyproject.toml", change_into=True),
468+
patch.object(
469+
PythonVersionCommand,
470+
"get_current_version",
471+
MagicMock(
472+
return_value=PEP440VersioningScheme.parse_version("1.2.3")
473+
),
474+
),
475+
patch.object(
476+
PythonVersionCommand,
477+
"version_file_path",
478+
new=PropertyMock(return_value=fake_version_py),
479+
),
480+
):
481+
with self.assertRaisesRegex(
482+
VersionError,
483+
"Provided version .* does not match the current version .*.",
484+
):
485+
cmd = PythonVersionCommand(PEP440VersioningScheme)
486+
version = PEP440VersioningScheme.parse_version("1.2.4")
487+
cmd.verify_version(version)
488+
489+
def test_provided_version_mismatch_with_poetry_version(self):
378490
fake_version_py = Path("foo.py")
379491
content = (
380492
'[tool.poetry]\nversion = "1.2.3"\n'
@@ -404,7 +516,34 @@ def test_provided_version_mismatch(self):
404516
version = PEP440VersioningScheme.parse_version("1.2.4")
405517
cmd.verify_version(version)
406518

407-
def test_verify_success(self):
519+
def test_verify_success_with_project_version(self):
520+
fake_version_py = Path("foo.py")
521+
content = (
522+
'[project]\nversion = "1.2.3"\n'
523+
'[tool.pontos.version]\nversion-module-file = "foo.py"'
524+
)
525+
526+
with (
527+
temp_file(content, name="pyproject.toml", change_into=True),
528+
patch.object(
529+
PythonVersionCommand,
530+
"get_current_version",
531+
MagicMock(
532+
return_value=PEP440VersioningScheme.parse_version("1.2.3")
533+
),
534+
),
535+
patch.object(
536+
PythonVersionCommand,
537+
"version_file_path",
538+
new=PropertyMock(return_value=fake_version_py),
539+
),
540+
):
541+
cmd = PythonVersionCommand(PEP440VersioningScheme)
542+
version = PEP440VersioningScheme.parse_version("1.2.3")
543+
544+
cmd.verify_version(version)
545+
546+
def test_verify_success_with_poetry_version(self):
408547
fake_version_py = Path("foo.py")
409548
content = (
410549
'[tool.poetry]\nversion = "1.2.3"\n'

0 commit comments

Comments
 (0)