{"id":5474,"library":"setupmeta","title":"Simplify your setup.py","description":"setupmeta is a Python library designed to significantly reduce boilerplate in `setup.py` files by automatically inferring project metadata from common project conventions. It extracts information like long description from `README.rst`/`README.md`, version from `__version__.py` or Git tags, and dependencies from `requirements.txt`. It encourages a DRY (Don't Repeat Yourself) approach to Python packaging. The current version is 3.9.0, and it is actively maintained with a regular release cadence.","status":"active","version":"3.9.0","language":"en","source_language":"en","source_url":"https://github.com/codrsquad/setupmeta","tags":["packaging","setuptools","metadata","build system","setup.py","dry"],"install":[{"cmd":"pip install setupmeta","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"setupmeta extends setuptools' functionality and integrates directly with setuptools.setup().","package":"setuptools","optional":false},{"reason":"Required for tag-based versioning features (e.g., `versioning=\"distance\"` or `\"post\"`). Git version 1.8.4 or higher is necessary.","package":"git","optional":true}],"imports":[{"note":"setupmeta is used by specifying it in `setup_requires` within the `setup()` call; it does not typically expose symbols for direct import into user code.","symbol":"setup","correct":"from setuptools import setup"}],"quickstart":{"code":"import os\nimport subprocess\n\n# Create a dummy project structure for demonstration\nproject_name = \"myproject_example\"\n\nos.makedirs(project_name, exist_ok=True)\nwith open(os.path.join(project_name, \"__init__.py\"), \"w\") as f:\n    f.write(\"__version__ = '0.0.1'\\n\")\n    f.write(\"__title__ = 'My Example Project'\\n\")\n\nwith open(os.path.join(project_name, \"../README.rst\"), \"w\") as f:\n    f.write(\"My Example Project\\n\")\n    f.write(\"===================\\n\\n\")\n    f.write(\"A simple project to demonstrate setupmeta.\")\n\nwith open(os.path.join(project_name, \"../requirements.txt\"), \"w\") as f:\n    f.write(\"click\\n\")\n    f.write(\"requests>=2.0.0\\n\")\n\n# Create a minimal setup.py\nsetup_py_content = \"\"\"\nfrom setuptools import setup\n\nsetup(\n    name=\"%s\",\n    versioning=\"distance\",  # Optional: activates tag-based versioning based on git\n    setup_requires=[\"setupmeta\"]  # This tells setuptools to use setupmeta\n)\n\"\"\" % project_name\n\nwith open(os.path.join(project_name, \"../setup.py\"), \"w\") as f:\n    f.write(setup_py_content)\n\nprint(f\"Project '{project_name}' and setup.py created. Now run: \")\nprint(f\"cd {os.path.dirname(os.path.abspath(__file__))}\")\nprint(f\"python setup.py explain # To see what setupmeta deduces\")\nprint(f\"python setup.py sdist bdist_wheel # To build distributions\")\n\n# Example of running the command programmatically (requires project setup from above)\n# try:\n#     # This command needs to be run from the directory containing setup.py\n#     # For this example, assume it's run in the parent directory of 'myproject_example'\n#     original_dir = os.getcwd()\n#     os.chdir(os.path.dirname(os.path.abspath(__file__)))\n#     subprocess.run([\"python\", \"setup.py\", \"explain\"], check=True)\n# finally:\n#     os.chdir(original_dir)\n","lang":"python","description":"setupmeta significantly shortens your `setup.py`. By placing `setup_requires=\"setupmeta\"` in your `setuptools.setup()` call, setupmeta will automatically deduce common project metadata from existing files (like `README.rst`, `__init__.py`, `requirements.txt`). The `python setup.py explain` command is invaluable for seeing exactly what metadata setupmeta has detected from your project's structure and files."},"warnings":[{"fix":"Ensure `git` is installed and meets the minimum version requirement in your build environment. If not using Git, specify the `version` explicitly in `setup()` or a dedicated `__version__.py` file.","message":"Using tag-based versioning (e.g., `versioning='distance'` or `versioning='post'`) requires Git to be installed and accessible, with a version of 1.8.4 or higher. If Git is not available or too old, version detection will fail, which can be a common issue in CI/CD environments or minimal Docker images.","severity":"gotcha","affected_versions":"All versions supporting `versioning` parameter."},{"fix":"Review your `setup.py` and remove any redundant metadata fields that you intend for setupmeta to deduce. Use `python setup.py explain` to inspect the final deduced metadata.","message":"Any parameters explicitly passed to `setuptools.setup()` will *always* take precedence over metadata deduced by setupmeta. This is by design, allowing granular control, but can lead to confusion if expected behavior is overridden by inadvertently explicit (or outdated) values in `setup.py`.","severity":"gotcha","affected_versions":"All versions."},{"fix":"For new projects or existing projects adopting modern packaging, ensure you have a `pyproject.toml` file that lists `setuptools` and `setupmeta` as build-time dependencies, e.g.: `[build-system]\\nrequires = [\"setuptools>=61.2\", \"wheel\", \"setupmeta\"]\\nbuild-backend = \"setuptools.build_meta\"`. This ensures setupmeta is available during the build process.","message":"setupmeta's primary integration point is via `setup_requires` in `setup.py`. While functional, the `setup_requires` mechanism is considered legacy in modern Python packaging (PEP 517/518), which prefers specifying build dependencies in `pyproject.toml` under `build-system.requires`. Not configuring `pyproject.toml` correctly may lead to issues with modern build tools or future `setuptools` versions.","severity":"deprecated","affected_versions":"All versions of setupmeta. Affects projects using `setuptools` >= 61.2.0, where stricter validation for `pyproject.toml` might occur."}],"env_vars":null,"last_verified":"2026-04-13T00:00:00.000Z","next_check":"2026-07-12T00:00:00.000Z"}