Package: binary_wheel_builder
binary-wheel-builderBuild deterministic python wheels to distribute CLI tools (third party or your own with python and make them easily usable using python code.Featuresdeterministic wheel file outputUse with Python Code or as CLIPrebuilt data sources for your binariesReady to release and ship your binariesWrapper for cli calls inside PythonExposes wheel as module entrypoint (python -m your_cli) and adds to path (your-cli)RequirementsPython 3.8+ for host running wheel buildFor target host every 3.x should workInstallation... with pip# with CLI dependenciespipinstallbinary_wheel_builder[cli]# as SDKpipinstallbinary_wheel_builder... with pipxpipxinstallbinary_wheel_builder[cli]UsageBuild with CLICreate your config file e. g.my-cli-wheel.yaml:package:my_cliexecutable:my-cli-binname:my-cliversion:0.0.1summary:My CLI provides nice and clean functionality on the terminaldescription:!FileContentREADME.mdlicense:MITrequires_python:">=3.8"classifier:-"License::OSIApproved::MITLicense"# Check https://pypi.org/classifiers/ for all availableproject_urls:# Set project urls as you like"Homepage":"https://github.com/my-org/my-cli""SourceCode":"https://github.com/my-org/my-cli,git""BugTracker":"https://github.com/my-org/my-cli/issues"source:!WheelSource# Fetch binary from GitHub releasesimplementation:binary_wheel_builder.api.wheel_sources.GithubReleaseBinarySourceproject_slug:my-org/my-cliversion:"0.0.1"tag_prefix:""# e.g. set to v when your tag is vX.Y.Z# Path of the binary relative to your package rootbinary_path:my_cli/my-cli-bin# Download file name based on platform the wheel is built forasset_name_mapping:!WellknownPlatform MAC_SILICON:"mycli-darwin-arm64"!WellknownPlatform MAC_INTEL:"mycli-darwin-amd64"!WellknownPlatform LINUX_GENERIC_x84_64:"my-cli-linux-amd64"!WellKnownPlatform LINUX_GENERIC_aarch64:"my-cli-linux-arm"# Supported platforms by the wheelplatforms:-!WellknownPlatformMAC_INTEL-!WellknownPlatformMAC_SILICON-!WellknownPlatformLINUX_GENERIC_x84_64-!WellKnownPlatformLINUX_GENERIC_aarch64Build your wheel for all platformsbinary-wheel-builder--wheel-specmy-cli-wheel.yamlUpload your wheel files usingtwine:twineupload-rpypidist/*Enjoy and consume your CLI as a packageBuild with Python codeIf you prefer to write Python Code you use almost the same structure:frompathlibimportPathfrombinary_wheel_builder.apiimportbuild_wheel,Wheel,well_known_platformsfrombinary_wheel_builder.api.wheel_sourcesimportGithubReleaseBinarySource# Add a custom github release sourceclassMyCliGithubReleaseSource(GithubReleaseBinarySource):def__init__(self,version:str):super().__init__("my-org/my-repo",version,{well_known_platforms.MAC_SILICON:"mycli-darwin-arm64",well_known_platforms.MAC_INTEL:"mycli-darwin-amd64",well_known_platforms.LINUX_GENERIC_x84_64:"my-cli-linux-amd64",well_known_platforms.LINUX_GENERIC_aarch64:"my-cli-linux-arm",},"my_cli/my-cli-bin")dist_folder=Path("dist")print("Built wheels:")forresultinbuild_wheel(Wheel(package="my_cli",executable="my-cli-bin",name="my-cli",version="0.0.1",summary='My CLI provides nice and clean functionality on the terminal',license='MIT',requires_python=">=3.9",classifier=['License :: OSI Approved :: MIT License',# Check https://pypi.org/classifiers/ for all available],project_urls={'Homepage':'https://github.com/my-org/my-cli','Source Code':'https://github.com/my-org/my-cli,git','Bug Tracker':'https://github.com/my-org/my-cli/issues',},source=MyCliGithubReleaseSource("0.0.1"),platforms=[well_known_platforms.MAC_INTEL,well_known_platforms.MAC_SILICON,well_known_platforms.LINUX_GENERIC_x84_64,well_known_platforms.LINUX_GENERIC_aarch64]),dist_folder):print(f" >{result.file_path}[{result.checksum}]")Afterwards upload with twine:
Upload your wheel files usingtwine:twineupload-rpypidist/*Using the generated wheelWith python module callpython-mmy_cliUsing wrapper in pathmy-cliUsing in Python code using exec utilsimportsubprocessfrommy_cliimportexec# Run process and prefix stdout and stderrexec.exec_with_templated_output(["--help"])# Create a subprocess, specifying how to handle stdout, stderrexec.create_subprocess(["--help"],stdout=subprocess.PIPE,stderr=subprocess.PIPE)# Perform command with suppressed output and return finished proces instance,# on that one can also check if the call was successfullyexec.exec_silently(["--version"])MotivationSometimes managing CLI dependencies for tooling etc. can become quite a pain.Also sometimes there are just so many options to distribute binaries, but Python is preinstalled on almost any nix
machine.
This opens great possibilities with using pip(x) to install dependencies or even reuse standalone CLI applications as
regular dependency in your code.DocumentationLibrary documentationContributingI love your input! I want to make contributing to this project as easy and transparent as possible, whether it's:Reporting a bugDiscussing the current state of the configurationSubmitting a fixProposing new featuresBecoming a maintainerTo get started please read theContribution Guidelines.DevelopmentRequirementsPython 3.8+PoetryTestIntegration Testspoetryrunpytestintegration_tests/Unit Testspoetryrunpytestbinary_wheel_builder/BuildpoetryinstallAlternativesUsing platform native package managementcurl'ing dependencies