Skip to content

Instantly share code, notes, and snippets.

@sjlongland
Last active June 27, 2023 03:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sjlongland/03def0794f832d3419d8c25ce2a5c213 to your computer and use it in GitHub Desktop.
Save sjlongland/03def0794f832d3419d8c25ce2a5c213 to your computer and use it in GitHub Desktop.
Mucking around with `distutils` command packages
#!/usr/bin/env python3
from distutils.cmd import Command
import json
def to_json(v):
if (v is None) or isinstance(v, (bool, int, str)):
return v
elif isinstance(v, list):
return [to_json(e) for e in v]
elif isinstance(v, dict):
return dict([
(to_json(k), to_json(e))
for k, e
in v.items()
])
else:
return repr(v)
class dumpmeta(Command):
"""
Dump the metadata for a `setup.py` script in JSON.
"""
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {}
for attr in dir(self.distribution):
if attr.startswith("_"):
continue
value = getattr(self.distribution, attr)
if hasattr(value, "__call__"):
if not attr.startswith("get_"):
continue
try:
value = value()
attr = attr[4:] # strip get_ prefix
except:
continue
metadata[attr] = to_json(value)
print (json.dumps(metadata, indent=4))
RC=0 stuartl@rikishi ~/projects/wicen/rfid/aioax25 $ python3 setup.py --command-package=dumpsetup dumpmeta
running dumpmeta
{
"author": "Stuart Longland VK4MSL",
"author_email": "me@vk4msl.id.au",
"cffi_modules": null,
"classifiers": [
"Development Status :: 2 - Pre-Alpha",
"Environment :: No Input/Output (Daemon)",
"Framework :: AsyncIO",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)",
"Operating System :: POSIX",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Communications :: Ham Radio"
],
"cmdclass": {
"dumpmeta": "<class 'dumpsetup.dumpmeta.dumpmeta'>"
},
"command_obj": {
"dumpmeta": "<dumpsetup.dumpmeta.dumpmeta object at 0x7f5951c3e310>"
},
"command_options": {
"tool:pytest": {
"log_cli": "('setup.cfg', 'true')"
},
"aliases": {},
"dumpmeta": {}
},
"command_packages": [
"distutils.command",
"dumpsetup"
],
"commands": [
"dumpmeta"
],
"common_usage": "Common commands: (see '--help-commands' for more)\n\n setup.py build will build the package underneath 'build/'\n setup.py install will install the package\n",
"contact": "Stuart Longland VK4MSL",
"contact_email": "me@vk4msl.id.au",
"data_files": null,
"dependency_links": [],
"description": "Asynchronous AX.25 interface in pure Python using asyncio",
"display_option_names": [
"help_commands",
"name",
"version",
"fullname",
"author",
"author_email",
"maintainer",
"maintainer_email",
"contact",
"contact_email",
"url",
"license",
"licence",
"description",
"long_description",
"platforms",
"classifiers",
"keywords",
"provides",
"requires",
"obsoletes"
],
"display_options": [
"('help-commands', None, 'list all available commands')",
"('name', None, 'print package name')",
"('version', 'V', 'print package version')",
"('fullname', None, 'print <package name>-<version>')",
"('author', None, \"print the author's name\")",
"('author-email', None, \"print the author's email address\")",
"('maintainer', None, \"print the maintainer's name\")",
"('maintainer-email', None, \"print the maintainer's email address\")",
"('contact', None, \"print the maintainer's name if known, else the author's\")",
"('contact-email', None, \"print the maintainer's email address if known, else the author's\")",
"('url', None, 'print the URL for this package')",
"('license', None, 'print the license of the package')",
"('licence', None, 'alias for --license')",
"('description', None, 'print the package description')",
"('long-description', None, 'print the long package description')",
"('platforms', None, 'print the list of platforms')",
"('classifiers', None, 'print the list of classifiers')",
"('keywords', None, 'print the list of keywords')",
"('provides', None, 'print the list of packages/modules provided')",
"('requires', None, 'print the list of packages/modules required')",
"('obsoletes', None, 'print the list of packages/modules made obsolete')"
],
"dist_files": [],
"dry_run": 0,
"eager_resources": null,
"entry_points": null,
"exclude_package_data": null,
"ext_modules": null,
"ext_package": null,
"extra_path": null,
"extras_require": {},
"fullname": "aioax25-0.0.12",
"cmdline_options": {},
"command_list": [
"('build', 'build everything needed to install')",
"('build_py', '\"build\" pure Python modules (copy to build directory)')",
"('build_ext', 'build C/C++ and Cython extensions (compile/link to build directory)')",
"('build_clib', 'build C/C++ libraries used by Python extensions')",
"('build_scripts', '\"build\" scripts (copy and fixup #! line)')",
"('clean', \"clean up temporary files from 'build' command\")",
"('install', 'install everything from build directory')",
"('install_lib', 'install all Python modules (extensions and pure Python)')",
"('install_headers', 'install C/C++ header files')",
"('install_scripts', 'install scripts (Python or otherwise)')",
"('install_data', 'install data files')",
"('sdist', 'create a source distribution (tarball, zip file, etc.)')",
"('register', 'register the distribution with the Python package index')",
"('bdist', 'create a built (binary) distribution')",
"('bdist_dumb', 'create a \"dumb\" built distribution')",
"('bdist_rpm', 'create an RPM distribution')",
"('check', 'perform some checks on the package')",
"('upload', 'upload binary package to PyPI')",
"('dumpmeta', '(no description available)')",
"('compile_catalog', 'compile message catalogs to binary MO files')",
"('extract_messages', 'extract localizable strings from the project code')",
"('init_catalog', 'create a new catalog based on a POT file')",
"('update_catalog', 'update message catalogs from a POT file')",
"('isort', 'Run isort on modules registered in setuptools')",
"('nosetests', 'Run unit tests using nosetests')",
"('alias', 'define a shortcut to invoke one or more commands')",
"('bdist_egg', 'create an \"egg\" distribution')",
"('develop', \"install package in 'development mode'\")",
"('dist_info', 'DO NOT CALL DIRECTLY, INTERNAL ONLY: create .dist-info directory')",
"('easy_install', 'Find/get/install Python packages')",
"('editable_wheel', 'DO NOT CALL DIRECTLY, INTERNAL ONLY: create PEP 660 editable wheel')",
"('egg_info', \"create a distribution's .egg-info directory\")",
"('install_egg_info', 'Install an .egg-info directory for the package')",
"('rotate', 'delete older distributions, keeping N newest files')",
"('saveopts', 'save supplied options to setup.cfg or other config file')",
"('setopt', 'set an option in setup.cfg or another config file')",
"('test', 'run unit tests after in-place build (deprecated)')",
"('upload_docs', 'Upload documentation to sites other than PyPi such as devpi')",
"('build_rust', 'build Rust extensions (compile/link to build directory)')",
"('clean_rust', 'clean Rust extensions (compile/link to build directory)')",
"('build_sphinx', 'Build Sphinx documentation')",
"('bdist_wheel', 'create a wheel distribution')"
],
"download_url": null,
"egg_cache_dir": "./.eggs",
"keywords": 0,
"license": 0,
"long_description": 0,
"maintainer": 0,
"maintainer_email": 0,
"name": 0,
"obsoletes": 0,
"platforms": 0,
"provides": 0,
"requires": 0,
"url": 0,
"version": 0,
"global_options": [
"('verbose', 'v', 'run verbosely (default)', 1)",
"('quiet', 'q', 'run quietly (turns verbosity off)')",
"('dry-run', 'n', \"don't actually do anything\")",
"('help', 'h', 'show detailed help message')",
"('no-user-cfg', None, 'ignore pydistutils.cfg in your home directory')"
],
"have_run": {
"dumpmeta": 0
},
"headers": null,
"help": 0,
"help_commands": 0,
"include_dirs": null,
"include_package_data": null,
"install_requires": [
"pyserial",
"signalslot",
"pyserial_asyncio"
],
"libraries": null,
"licence": 0,
"message_extractors": null,
"metadata": "<distutils.dist.DistributionMetadata object at 0x7f59521508d0>",
"namespace_packages": null,
"negative_opt": {
"quiet": "verbose"
},
"package_data": {},
"package_dir": {},
"packages": [
"aioax25",
"aioax25.aprs"
],
"password": "",
"pbr": null,
"py_modules": null,
"python_requires": null,
"rust_extensions": null,
"script_args": [
"--command-package=dumpsetup",
"dumpmeta"
],
"script_name": "setup.py",
"scripts": null,
"setup_requires": [],
"src_root": null,
"test_loader": null,
"test_runner": null,
"test_suite": null,
"tests_require": null,
"use_2to3": null,
"use_calver": null,
"use_incremental": null,
"use_scm_version": null,
"verbose": 1,
"want_user_cfg": true,
"zip_safe": null
}
https://docs.python.org/3/distutils/apiref.html#module-distutils.command.build
https://docs.python.org/3/distutils/apiref.html#creating-a-new-distutils-command
The referenced 'template' is very sparse:
https://github.com/pypa/distutils/blob/main/distutils/command/command_template
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment