Skip to content

Commit dcb31b8

Browse files
authored
Merge pull request #381 from DoubleML/sk-publishing
Add dynamic versioning
2 parents 57ea4d2 + 4c42c0e commit dcb31b8

File tree

7 files changed

+110
-8
lines changed

7 files changed

+110
-8
lines changed

.github/workflows/deploy_pkg.yml

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
release:
55
types:
66
- published
7+
workflow_dispatch:
78

89
jobs:
910
build:
@@ -14,6 +15,7 @@ jobs:
1415
- uses: actions/checkout@v4
1516
with:
1617
persist-credentials: false
18+
fetch-depth: 0 # Required for dynamic versioning
1719

1820
- name: Install python
1921
uses: actions/setup-python@v5
@@ -56,11 +58,38 @@ jobs:
5658
uses: pypa/gh-action-pypi-publish@release/v1
5759
with:
5860
repository-url: https://test.pypi.org/legacy/
61+
skip-existing: true # Prevents failure on re-runs
62+
63+
verify-testpypi:
64+
name: Verify TestPyPI Install 🕵️
65+
needs: publish-to-testpypi
66+
runs-on: ubuntu-latest
67+
steps:
68+
- uses: actions/setup-python@v5
69+
with:
70+
python-version: "3.12"
71+
72+
- name: Wait for TestPyPI indexing
73+
run: sleep 60
74+
75+
- name: Install from TestPyPI
76+
# --extra-index-url allows pip to find dependencies (pandas, numpy) on the real PyPI
77+
if: github.event_name == 'release'
78+
run: pip install --pre --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ "DoubleML==${{ github.ref_name }}"
79+
80+
- name: Install from TestPyPI (workflow_dispatch)
81+
# For manual runs, install the latest pre-release version
82+
if: github.event_name == 'workflow_dispatch'
83+
run: pip install --pre --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ DoubleML
84+
85+
- name: Import Smoke Test
86+
run: python -c "import doubleml; print(f'Successfully imported DoubleML version {doubleml.__version__}')"
5987

6088
publish-to-pypi:
6189
name: Publish to PyPI 🚀
62-
needs: publish-to-testpypi
90+
needs: verify-testpypi
6391
runs-on: ubuntu-latest
92+
if: github.event_name == 'release' # Do not publish on workflow_dispatch
6493
environment:
6594
name: pypi
6695
url: https://pypi.org/p/DoubleML
@@ -76,3 +105,22 @@ jobs:
76105

77106
- name: Publish to PyPI
78107
uses: pypa/gh-action-pypi-publish@release/v1
108+
109+
verify-pypi:
110+
name: Verify PyPI Install 🕵️
111+
needs: publish-to-pypi
112+
runs-on: ubuntu-latest
113+
if: github.event_name == 'release'
114+
steps:
115+
- uses: actions/setup-python@v5
116+
with:
117+
python-version: "3.12"
118+
119+
- name: Wait for PyPI indexing
120+
run: sleep 60
121+
122+
- name: Install from PyPI
123+
run: pip install "DoubleML==${{ github.ref_name }}"
124+
125+
- name: Import Smoke Test
126+
run: python -c "import doubleml; print(f'Successfully imported DoubleML version {doubleml.__version__}')"

.github/workflows/pytest.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
steps:
3333
- uses: actions/checkout@v4
3434
with:
35-
fetch-depth: 2
35+
fetch-depth: 0 # allow version retrieval with setuptools_scm
3636

3737
- name: Set up Python ${{ matrix.config.python-version }}
3838
uses: actions/setup-python@v5

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@ MANIFEST
3131
*.vscode
3232
.flake8
3333
.coverage
34+
35+
# Setuptools SCM
36+
doubleml/_version.py

doc/conf.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import os
1414
import sys
1515

16+
import doubleml
17+
1618
sys.path.insert(0, os.path.abspath(".."))
1719

1820

@@ -23,7 +25,7 @@
2325
author = "Bach, P., Chernozhukov, V., Klaassen, S., Kurz, M. S., and Spindler, M."
2426

2527
# The full version, including alpha/beta/rc tags
26-
release = "0.12.dev0"
28+
release = doubleml.__version__
2729

2830

2931
# -- General configuration ---------------------------------------------------

doubleml/__init__.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import importlib.metadata
2-
31
from .data import DoubleMLClusterData, DoubleMLData, DoubleMLDIDData, DoubleMLPanelData, DoubleMLRDDData, DoubleMLSSMData
42
from .did.did import DoubleMLDID
53
from .did.did_cs import DoubleMLDIDCS
@@ -47,4 +45,12 @@
4745
"DoubleMLLPLR",
4846
]
4947

50-
__version__ = importlib.metadata.version("doubleml")
48+
try:
49+
from ._version import version as __version__
50+
except ImportError:
51+
import importlib.metadata
52+
53+
try:
54+
__version__ = importlib.metadata.version("doubleml")
55+
except importlib.metadata.PackageNotFoundError:
56+
__version__ = "0.0.0+unknown"

doubleml/tests/test_init.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import importlib
2+
import sys
3+
from unittest.mock import patch
4+
5+
import pytest
6+
7+
8+
@pytest.mark.ci
9+
def test_version_from_version_file():
10+
"""Test version is imported from _version.py when available."""
11+
import doubleml
12+
13+
assert hasattr(doubleml, "__version__")
14+
assert isinstance(doubleml.__version__, str)
15+
16+
17+
@pytest.mark.ci
18+
def test_version_fallback_to_metadata():
19+
"""Test fallback to importlib.metadata when _version.py is missing."""
20+
with patch.dict(sys.modules, {"doubleml._version": None}):
21+
with patch("importlib.metadata.version", return_value="1.2.3"):
22+
# Re-import to trigger the fallback
23+
importlib.reload(importlib.import_module("doubleml"))
24+
import doubleml
25+
26+
assert doubleml.__version__ == "1.2.3"
27+
28+
29+
@pytest.mark.ci
30+
def test_version_fallback_to_unknown():
31+
"""Test fallback to 0.0.0+unknown when package not found."""
32+
mock_error = importlib.metadata.PackageNotFoundError()
33+
with patch.dict(sys.modules, {"doubleml._version": None}):
34+
with patch("importlib.metadata.version", side_effect=mock_error):
35+
importlib.reload(importlib.import_module("doubleml"))
36+
import doubleml
37+
38+
assert doubleml.__version__ == "0.0.0+unknown"

pyproject.toml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
[build-system]
2-
requires = ["setuptools>=65", "wheel"]
2+
requires = ["setuptools>=80", "wheel", "setuptools-scm>=8"]
33
build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "DoubleML"
7-
version = "0.12.dev0"
7+
dynamic = ["version"]
88
description = "Double Machine Learning in Python"
99
readme = {file = "README.md", content-type = "text/markdown"}
1010
license = {file = "LICENSE"}
@@ -57,6 +57,11 @@ Documentation = "https://docs.doubleml.org"
5757
Source = "https://github.com/DoubleML/doubleml-for-py"
5858
"Bug Tracker" = "https://github.com/DoubleML/doubleml-for-py/issues"
5959

60+
[tool.setuptools_scm]
61+
version_scheme = "guess-next-dev"
62+
local_scheme = "dirty-tag"
63+
write_to = "doubleml/_version.py"
64+
6065
[tool.pytest.ini_options]
6166
markers = [
6267
"ci: mark a test as a continuous integration test which will be executed in github actions.",

0 commit comments

Comments
 (0)