Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using environment variables in `pyproject.toml` for versioning

I am trying to migrate my package from setup.py to pyproject.toml and I am not sure how to do the dynamic versioning in the same way as before. Currently I can pass the development version using environment variables when the build is for development.

The setup.py file looks similar to this:

import os

from setuptools import setup

import my_package


if __name__ == "__main__":
    dev_version = os.environ.get("DEV_VERSION")
    version = dev_version if dev_version else f"{my_package.__version__}"
    
    setup(
        name="my_package",
        version=version,
        ...
    )

Is there a way to do similar thing when using pyproject.toml file?

like image 417
Ilya Avatar asked Nov 17 '25 21:11

Ilya


2 Answers

At the time that I write this answer, the most genuinely valid approach on how to do that is to go ahead and write your pyproject.toml as you normally would, but instead of having a version = "..." field you add a dynamic = ["version"].

Then you can keep a very minimal setup.py file which only resolves the dynamic value of version. For example:

# pyproject.toml
[project]
name = "hello-world"
readme = "README.md"
authors = [...]
dependencies = [...]
dynamic = ["version"]

[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta:__legacy__"
# The difference between `__legacy__` and the regular `build_meta`
# is that `__legacy__` does the equivalent of
# `sys.path.insert(0, os.path.dirname(__file__))`.
# This allows you to `import` your modules from the `CWD`.
# If you don't like using `__legacy__` you can
# manually add `CWD` to `sys.path` inside your `setup.py`.
# setup.py
import os
from setuptools import setup

import my_package

dev_version = os.environ.get("DEV_VERSION")

setup(
  version=dev_version if dev_version else f"{my_package.__version__}"
)

These are my remarks about this approach:

  • Setuptools allows you to keep all your static metadata/configuration parameters in pyproject.toml and at the same time use logic to compute all the dynamic parts in setup.py. Setuptools docs explicitly say:

    Metadata and configuration supplied via setup() is complementary to ... the information present in ... pyproject.toml.

    It is important however to remember to write dynamic = [...] in accordance with the spec to allow setuptools to overwrite any value that can be specified via the [project] table.

  • setup.py is only deprecated as a "runnable CLI tool" that can be invoked directly with python setup.py .... But it is still a perfectly valid configuration file in the same way that conftest.py is a valid configuration file for pytest and noxfile.py is a configuration file for nox (you usually don't call python conftest.py or python noxfile.py...). One evidence for this is article https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html written by one of the authors of PEP 621 (which stablishes the [project] table in pyproject.toml) and maintainer of setuptools.

  • Note that I used in the example build-backend = "setuptools.build_meta:__legacy__" instead of build-backend = "setuptools.build_meta". This happens because __legacy__ tries to emulate the "side-effect" behaviour of running python setup.py ..., i.e. to add CWD to sys.path. If you don't like that, you can manipulate sys.path explicitly in your setup.py file before the relevant imports.

like image 59
Anderson Bravalheri Avatar answered Nov 19 '25 13:11

Anderson Bravalheri


Another alternative that might be worth considering for your use case, if you use Git, is to use setuptools_scm. It uses your git tags to perform dynamic versioning. Your pyproject.toml would look something like this:

[build-system]
requires = ["setuptools", "setuptools-scm"]
build-backend = "setuptools.build_meta"

[tool.setuptools_scm]
"version_scheme" = "post-release"
"local_scheme" = "no-local-version"
"write_to" = "mypackage/version.py"

[tool.setuptools.package-dir]
mypackage = "mypackage"

[project]
name = "mypackage"
...
dynamic = ["version"]
like image 22
Vorticity Avatar answered Nov 19 '25 13:11

Vorticity



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!