python
setuptools
setup.py
package-version
version-management

How can I get the version defined in setup.py setuptools in my package?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If your package needs to know its own version, the wrong approach is to import setup.py at runtime. The reliable approach is to keep the version in normal package code and let setup.py read from that source, or to query installed package metadata after installation.

Do Not Import setup.py From Your Package

setup.py is a build script, not an application module. Importing it at runtime can trigger packaging logic, dependency side effects, or path issues that do not belong inside your package.

Instead of asking "how do I read the version from setup.py," the better design is "how do I make setup.py and my package share one source of truth."

Put the Version in Package Code

A common pattern is to define the version in a module:

python
# mypackage/__init__.py
__version__ = "1.4.0"

Then read that value in setup.py:

python
1from pathlib import Path
2from setuptools import setup
3
4namespace = {}
5version_file = Path(__file__).parent / "mypackage" / "__init__.py"
6exec(version_file.read_text(), namespace)
7
8setup(
9    name="mypackage",
10    version=namespace["__version__"],
11    packages=["mypackage"],
12)

Now your package can access __version__ directly:

python
from mypackage import __version__

print(__version__)

This keeps the value in ordinary Python code instead of forcing runtime code to inspect packaging metadata.

Use a Dedicated _version.py File

Many projects prefer not to store extra metadata in __init__.py. A small dedicated module is cleaner:

python
# mypackage/_version.py
__version__ = "1.4.0"

Package import:

python
from ._version import __version__

Build script:

python
1from pathlib import Path
2from setuptools import setup
3
4namespace = {}
5version_path = Path(__file__).parent / "mypackage" / "_version.py"
6exec(version_path.read_text(), namespace)
7
8setup(
9    name="mypackage",
10    version=namespace["__version__"],
11    packages=["mypackage"],
12)

This pattern makes the ownership of the version string obvious and avoids accidental import-time side effects from the rest of the package.

Query the Installed Package Version

If the package is already installed and you want the installed version, use importlib.metadata:

python
from importlib.metadata import version

print(version("mypackage"))

This reads package metadata from the installed distribution, not from setup.py. That is the right choice when you want to know what the environment actually installed.

For Python versions before importlib.metadata was built in, older projects often used pkg_resources, but importlib.metadata is the lighter modern choice.

Why a Single Source of Truth Matters

Version drift is easy to create if you hardcode the value in more than one place. For example:

  • 'setup.py says 1.4.0'
  • 'mypackage.__version__ says 1.3.9'
  • The installed wheel metadata says something else

That leads to confusing bug reports and deployment mistakes. The solution is to define the version once and reference it everywhere else.

Practical Recommendation

For a setuptools-based project that still uses setup.py, the best baseline is:

  1. Store __version__ in package code.
  2. Read that value from setup.py.
  3. Use importlib.metadata.version() when you need the installed distribution version.

If you are maintaining a modern packaging setup, you may eventually move to pyproject.toml, but the single-source principle remains the same.

Common Pitfalls

  • Importing setup.py inside the package at runtime.
  • Duplicating the version string in multiple files and letting them drift apart.
  • Reading installed package metadata when the real question is about source-tree version during development.
  • Putting complex imports in the file that defines __version__, which makes setup-time reads fragile.
  • Assuming setup.py is the authoritative runtime source rather than a build-time consumer of version data.

Summary

  • Do not import setup.py from your package just to read the version.
  • Keep the version in package code, usually as __version__.
  • Let setup.py read that version so there is only one source of truth.
  • Use importlib.metadata.version() when you need the installed package version.
  • A simple _version.py module is often the cleanest implementation.

Course illustration
Course illustration

All Rights Reserved.