Subpar is a utility for creating self-contained python executables. It is designed to work well with Bazel.

Overview

Subpar

Build Status

Subpar is a utility for creating self-contained python executables. It is designed to work well with Bazel.

Status

Subpar is currently owned by the maintainers of bazelbuild/rules_python, which depends on it. It is not being actively developed beyond what is needed to keep compatibility with rules_python.

Historically, subpar was the only way to produce a deployable Python artifact in Bazel. This is no longer quite true; --build_python_zip allows you to create executable Python zip artifacts with the standard py_binary rule. Subpar still supports some use cases --build_python_zip doesn't: In particular, it allows you to build archives of specific targets without using a global command-line flag, and in some cases the archives can run in-place without extraction.

Setup

  • Add the following to your WORKSPACE file:
git_repository(
    name = "subpar",
    remote = "https://github.com/google/subpar",
    tag = "1.0.0",
)
  • Add the following to the top of any BUILD files that declare par_binary() rules:
load("@subpar//:subpar.bzl", "par_binary")

Usage

par_binary() is a drop-in replacement for py_binary() in your BUILD files that also builds a self-contained, single-file executable for the application, with a .par file extension.

To build the .par file associated with a par_binary(name=myname) rule, do

bazel build //my/package:myname.par

The .par file is created alongside the python stub and .runfiles directories that py_binary() creates, but is independent of them. It can be copied to other directories or machines, and executed directly without needing the .runfiles directory. The body of the .par file contains all the srcs, deps, and data files listed.

Limitations:

  • C extension modules in 'deps' is not yet supported
  • Automatic re-extraction of '.runfiles' is not yet supported
  • Does not include a copy of the Python interpreter ('hermetic .par')

Example

Given a BUILD file with the following:

load("@subpar//:subpar.bzl", "par_binary")

par_binary(
    name = 'foo',
    srcs = ['foo.py', 'bar.py'],
    deps = ['//baz:some_py_lib'],
    data = ['quux.dat'],
)

Run the following build command:

bazel build //package:foo.par

This results in the following files being created by bazel build:

bazel-bin/
    package/
        foo
        foo.par
        foo.runfiles/
            ...

The .par file can be copied, moved, or renamed, and still run like a compiled executable file:

$ scp bazel-bin/package/foo.par my-other-machine:foo.par
$ ssh my-other-machine ./foo.par

System Requirements

  • Python Versions: CPython versions 2.7.6+
  • Operating Systems: Debian-derived Linux, including Ubuntu and Goobuntu.

DISCLAIMER

This is not an official Google product, it is just code that happens to be owned by Google.

Comments
  • Build fails with bazel 0.25 --incompatible_use_python_toolchains

    Build fails with bazel 0.25 --incompatible_use_python_toolchains

    It seems like the first line in the par has an incomplete path to the wrapper script:

    $ head bazel-bin/compiler/compiler.par
    #!bazel_tools/tools/python/py2wrapper.sh
    PK
    
    opened by tmc 19
  • Handle python packages that have shared object files

    Handle python packages that have shared object files

    Some python packages have shared object files that are required to be extracted in order for the system to execute them. This patch extracts all packages that include shared objects to a tmp dir so that the so files can be run properly.

    opened by jac-stripe 14
  • PAR picks up system-installed version instead of bundled version

    PAR picks up system-installed version instead of bundled version

    In my PR to add PIP support to Bazel you can reproduce this as shown below.

    On a system with:

    $ pip --version
    pip 1.5.4 from /usr/lib/python2.7/dist-packages (python 2.7)
    

    (I must have gotten this through apt-get or some other super-slow release channel)

    If I bazel run the py_binary form, no warning:

    rules_python$ bazel run rules_python:piptool --  --name foo --input $PWD/examples/helloworld/requirements.txt --directory /tmp/pip/ --output /tmp/requirements.bzl
    INFO: Analysed target //rules_python:piptool (0 packages loaded).
    INFO: Found 1 target...
    Target //rules_python:piptool up-to-date:
      bazel-bin/rules_python/piptool
    INFO: Elapsed time: 0.184s, Critical Path: 0.00s
    INFO: Build completed successfully, 1 total action
    
    INFO: Running command line: bazel-bin/rules_python/piptool --name foo --input /home/mattmoor/rules_python/examples/helloworld/requirements.txt --directory /tmp/pip/ --output /tmp/requirements.bzl
    Collecting futures>=3.1 (from -r /home/mattmoor/rules_python/examples/helloworld/requirements.txt (line 1))
      File was already downloaded /tmp/pip/futures-3.1.1-py2-none-any.whl
    Skipping futures, due to already being wheel.
    

    If I bazel run the .par target, I get a warning:

    rules_python$ bazel run rules_python:piptool.par --  --name foo --input $PWD/examples/helloworld/requirements.txt --
    directory /tmp/pip/ --output /tmp/requirements.bzl
    INFO: Analysed target //rules_python:piptool.par (0 packages loaded).
    INFO: Found 1 target...
    Target //rules_python:piptool.par up-to-date:
      bazel-bin/rules_python/piptool.par
    INFO: Elapsed time: 0.204s, Critical Path: 0.01s
    INFO: Build completed successfully, 1 total action
    
    INFO: Running command line: bazel-bin/rules_python/piptool.par --name foo --input /home/mattmoor/rules_python/examples/helloworld/requirements.txt --directory /tmp/pip/ --output /tmp/requirements.bzl
    Collecting futures>=3.1 (from -r /home/mattmoor/rules_python/examples/helloworld/requirements.txt (line 1))
      File was already downloaded /tmp/pip/futures-3.1.1-py2-none-any.whl
    Skipping futures, due to already being wheel.
    You are using pip version 1.5.4, however version 9.0.1 is available.
    You should consider upgrading via the 'pip install --upgrade pip' command.
    

    Happy to provide more info as needed.

    opened by mattmoor 12
  • Cleanup for Bazel future changes

    Cleanup for Bazel future changes

    Tested: bazel0.20 test //... --all_incompatible_changes

    • Reformatted file with Buildifier
    • Applied Buildifier automated fixes
    • Fixed other issues (depsets are not iterable, tools are separate from other inputs)

    Progress towards https://github.com/bazelbuild/rules_python/issues/134

    opened by laurentlb 7
  • Python interpreter can now be overridden

    Python interpreter can now be overridden

    In case the Python runtime used to build a par is not exactly the same path as the target interpreter, this allows the interpreter to be explicitly set instead of inferred from the stub file.

    Example:

    par_binary(
        name = "mybinary",
        srcs = ["mybinary.py"],
        compiler_args = ["--interpreter", "/usr/bin/env python3.6"],
    )
    
    opened by apt-itude 7
  • add default shell env

    add default shell env

    This pull request simply add default shell envs to par_* rules.

    Under a lot of customized environments, the process-wrapper and sandbox of Bazel will not carry the shell envs by default. So very often, par rules will fail for this reason. This PR add the default_shell_env to the rule.

    opened by yliu120 6
  • Fix incompatibility with Python Toolchains

    Fix incompatibility with Python Toolchains

    Fixes #98 by detecting the default toolchain wrappers and replacing with env versions. I'm perhaps not totally happy with how it's done, as any change in the path to these wrappers would break things again, so open to suggestions. Also, for Python 2 should we use /usr/bin/python or /usr/bin/python2, I prefer the latter but don't know how this behaves on all systems?

    Also, now that we have PyInfo provider, the import paths are passed directly from Starlark to the compiler, removing a bit of fragility in parsing the stub file for those. However, I can't see a way to pass the interpreter directly, as this doesn't appear to be available to Starlark. This removed a TODO with reference b/29227737, if that means anything internally?

    Tested with both the default toolchain and a custom one to ensure the correct shebang ends up at the top of the par file. It might be worth adding a test that excercises this, but until the toolchains flag is flipped in CI the test will always fail.

    opened by aaliddell 5
  • Propagate tags via par_*** macros

    Propagate tags via par_*** macros

    This updates the par_*** macros to propagate tags to the underlying rules. This is important, as currently the manual tag doesn't work fro the par_*** macros.

    opened by andyscott 4
  • `from __future__` in the main file causes SyntaxError

    `from __future__` in the main file causes SyntaxError

    If the main python script contains from __future__ import ... statements, running par file causes the following error:

    $ ./train.par
    Traceback (most recent call last):
      File "/usr/lib/python2.7/runpy.py", line 165, in _run_module_as_main
        mod_name, loader, code, fname = _get_main_module_details(_Error)
      File "/usr/lib/python2.7/runpy.py", line 133, in _get_main_module_details
        return _get_module_details(main_name)
      File "/usr/lib/python2.7/runpy.py", line 119, in _get_module_details
        code = loader.get_code(mod_name)
      File "./train.par/__main__.py", line 74
    SyntaxError: from __future__ imports must occur at the beginning of the file
    

    This seems to be due to the boilerplate added by subpar compiler before the __future statements.:

    # Boilerplate added by subpar/compiler/python_archive.py
    from subpar.runtime import support as _
    _.setup(import_roots=[u'__main__', u'six_archive'])
    del _
    # End boilerplate
    
    opened by sjincho 4
  • Add par_test variant of par_binary, passthrough testonly attr

    Add par_test variant of par_binary, passthrough testonly attr

    This makes it possible to run py_tests as .par files, which is occasionally useful for testing code that behaves differently when called from within a zipped executable. It also enables the uncommon (but valid, I'm pretty sure) scenario of having a par_binary definition with testonly=True set.

    opened by benley 4
  • compiler can't find python binary

    compiler can't find python binary

    On some systems I see errors like the following:

    benle[email protected]:~/pm/pi-k8s$ bazel build  @subpar//compiler:compiler.par --verbose_failures --strategy=PythonCompile=standalone                               
    INFO: Found 1 target...           
    ERROR: /home/benley/.cache/bazel/_bazel_benley/9e259f4d6c3d097d1daa32f0372be769/external/subpar/compiler/BUILD:40:1: Building par file @subpar//compiler:compiler.par failed: compiler failed: error executing command                                                                
      (cd /home/benley/.cache/bazel/_bazel_benley/9e259f4d6c3d097d1daa32f0372be769/execroot/pi-k8s && \                                        
      exec env - \                    
      bazel-out/host/bin/external/subpar/compiler/compiler --manifest_file bazel-out/local-fastbuild/bin/external/subpar/compiler/compiler.par_SOURCES --outputpar bazel-out/local-fastbuild/bin/external/subpar/compiler/compiler.par --stub_file bazel-out/local-fastbuild/bin/external/subpar/compiler/compiler external/subpar/compiler/compiler.py): com.google.devtools.build.lib.shell.BadExitStatusException: Process exited with status 1.                    
    Traceback (most recent call last):
      File "bazel-out/host/bin/external/subpar/compiler/compiler", line 168, in <module>                                                       
        Main()                        
      File "bazel-out/host/bin/external/subpar/compiler/compiler", line 148, in Main                                                           
        raise AssertionError('Could not find python binary: ' + PYTHON_BINARY)                                                                 
    AssertionError: Could not find python binary: python                 
    Target @subpar//compiler:compiler.par failed to build                
    INFO: Elapsed time: 0.103s, Critical Path: 0.03s
    

    On others it works.

    The difference appears to be in the behaviour of env - across linux distributions. On Ubuntu and Debian, the resulting "empty" environment still has $PATH set to a default value:

    [email protected]:~$ env - bash -c set
    BASH=/bin/bash
    BASHOPTS=cmdhist:complete_fullquote:extquote:force_fignore:hostcomplete:interactive_comments:progcomp:promptvars:sourcepath
    BASH_ALIASES=()
    BASH_ARGC=()
    BASH_ARGV=()
    BASH_CMDS=()
    BASH_EXECUTION_STRING=set
    BASH_LINENO=()
    BASH_SOURCE=()
    BASH_VERSINFO=([0]="4" [1]="3" [2]="30" [3]="1" [4]="release" [5]="i586-pc-linux-gnu")
    BASH_VERSION='4.3.30(1)-release'
    DIRSTACK=()
    EUID=1009
    GROUPS=()
    HOSTNAME=aram
    HOSTTYPE=i586
    IFS=$' \t\n'
    MACHTYPE=i586-pc-linux-gnu
    OPTERR=1
    OPTIND=1
    OSTYPE=linux-gnu
    PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:.
    PPID=6844
    PS4='+ '
    PWD=/home/benley
    SHELL=/bin/bash
    SHELLOPTS=braceexpand:hashall:interactive-comments
    SHLVL=1
    TERM=dumb
    UID=1009
    _=bash
    

    (same output on ubuntu 16.04)

    On at least one other distro (NixOS linux), there seems to be no such default PATH:

    [email protected]:~$ env - bash -c set
    BASH=/run/current-system/sw/bin/bash
    BASHOPTS=cmdhist:complete_fullquote:extquote:force_fignore:hostcomplete:interactive_comments:progcomp:promptvars:sourcepath
    BASH_ALIASES=()
    BASH_ARGC=()
    BASH_ARGV=()
    BASH_CMDS=()
    BASH_EXECUTION_STRING=set
    BASH_LINENO=()
    BASH_SOURCE=()
    BASH_VERSINFO=([0]="4" [1]="4" [2]="12" [3]="1" [4]="release" [5]="x86_64-unknown-linux-gnu")
    BASH_VERSION='4.4.12(1)-release'
    DIRSTACK=()
    EUID=1000
    GROUPS=()
    HOSTNAME=alnitak
    HOSTTYPE=x86_64
    IFS=$' \t\n'
    MACHTYPE=x86_64-unknown-linux-gnu
    OPTERR=1
    OPTIND=1
    OSTYPE=linux-gnu
    PATH=/no-such-path
    PPID=3931
    PS4='+ '
    PWD=/home/benley/pm/pi-k8s
    SHELL=/run/current-system/sw/bin/bash
    SHELLOPTS=braceexpand:hashall:interactive-comments
    SHLVL=1
    TERM=dumb
    UID=1000
    _=bash
    

    It's not entirely clear to me why PATH gets set like that, but it certainly breaks the compiler's build.

    opened by benley 4
  • Bump setuptools from 5.5.1 to 65.5.1 in /tests

    Bump setuptools from 5.5.1 to 65.5.1 in /tests

    Bumps setuptools from 5.5.1 to 65.5.1.

    Release notes

    Sourced from setuptools's releases.

    v65.5.1

    No release notes provided.

    v65.5.0

    No release notes provided.

    v65.4.1

    No release notes provided.

    v65.4.0

    No release notes provided.

    v65.3.0

    No release notes provided.

    v65.2.0

    No release notes provided.

    v65.1.1

    No release notes provided.

    v65.1.0

    No release notes provided.

    v65.0.2

    No release notes provided.

    v65.0.1

    No release notes provided.

    v65.0.0

    No release notes provided.

    v64.0.3

    No release notes provided.

    v64.0.2

    No release notes provided.

    v64.0.1

    No release notes provided.

    v64.0.0

    No release notes provided.

    v63.4.3

    No release notes provided.

    v63.4.2

    No release notes provided.

    ... (truncated)

    Changelog

    Sourced from setuptools's changelog.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Shridevinb/windows par

    Shridevinb/windows par

    This change includes a fix to #39

    • Remove the stubfile parsing when the interpreter is specified.
    • And use the interpreter as the first argument while running the compiler.par on windows, because compiler.par is not recognised as win32 application and it requires the python to invoke it. For others, the shebang is specified in the file and it works.
    opened by shridevinb 10
  • Subpar is failing on Bazel CI since the upgrade to Ubuntu 20.04

    Subpar is failing on Bazel CI since the upgrade to Ubuntu 20.04

    Ubuntu 20.04 uses Python 3, which might be what's causing this.

    Lots of test failures, see https://buildkite.com/bazel/subpar/builds/7413#7f8773f9-2385-4244-8a00-da4c4dd9a2ab

    opened by Wyverald 1
  • Python cannot run Subpars larger than 2GiB because they are Zip64 formatted.

    Python cannot run Subpars larger than 2GiB because they are Zip64 formatted.

    This is very unlikely to be fixed due to Subpar's maintenance status but it's good to document it here to potentially save others some debugging time.


    Any .par written by Subpar using zipfile will be ZIP64 format whenever the file size exceeds ZIP64_LIMIT = (1 << 31) - 1. See https://github.com/python/cpython/blob/ffd87b7093109c279caf8e3ca060f408a102388a/Lib/zipfile.py#L56

    As of Python 3.10 zipimport does not support ZIP64. The module function in question is _read_directory: https://github.com/python/cpython/blob/bb3e0c240bc60fe08d332ff5955d54197f79751c/Lib/zipimport.py#L408-L468

    On attempting to run the subpar like python3 foo.par you will get an obscure error:

    can't find '__main__' module in /foo.par
    

    If you do python3 -vv foo.par you will see a logline:

    # zipimport: found 0 names in /abs/path/to/foo.par
    

    Python's zipimport._read_directory has failed to find any files because it has incorrectly calculated the byte offset for the first ZIP record file. It has incorrectly calculated the byte offset because it does not understand ZIP64.


    So if you see this error check the size of your .par.

    par_size = ...
    max_bytes = (1 << 31) -1
    if max_bytes < par_size:
        print("bad news")
    

    cc @ducthienbui97 who completed this bug investigation.

    opened by thundergolfer 0
  • Support hermetically built python interperters

    Support hermetically built python interperters

    Subpar fails when py_runtime is provided a label for interpreter location, see: https://github.com/google/subpar/issues/98#issuecomment-529904795

    @thundergolfer brings up the point that for nix builds, or other hermetic python builds, subpar will not work. Ideally subpar should bundle the interpreter binary into the par for these instances.

    I see the subpar is not longer being actively maintained, so no big deal. I think it's still important to have this issue open in case other people run into the same issue.

    opened by dmadisetti 0
  • Don't parse stub file if interpreter is explicitly provided

    Don't parse stub file if interpreter is explicitly provided

    It seems like --stub_file is only parsed to derive which interpreter is being used. Correct me if I'm wrong, but it seems like passing in --interpreter should short-circuit parsing that file. Seems like this will allow for using in-workspace py_runtime definitions as long as the interpreter is specified explicitly in the parfile() rule.

    I might be missing some important context though.

    opened by dflems 5
Releases(2.0.0)
  • 2.0.0(May 14, 2019)

    Notable fixes:

    • Now works with the default (autodetecting) Python toolchain in Bazel 0.25+
    • Fails fast when attempting to use a Python runtime from runfiles rather than a system-installed runtime. See #98.

    Incompatible changes:

    • Minimum Bazel version bumped to 0.23.0
    Source code(tar.gz)
    Source code(zip)
  • 1.3.0(Apr 26, 2018)

    New features:

    • Add compiler_args flag to par_binary. This allows one to pass arbitrary flags to the compiler executable.

    Notable fixes:

    • Python 2.6 compatibility
    • MacOS compatibility
    • Python 3 compatibility
    Source code(tar.gz)
    Source code(zip)
  • 1.2.0(Jan 30, 2018)

    New features:

    • Add zip_safe=False flag to par_binary. This unpacks the par file contents at runtime, allowing you to import C extension modules and access data files natively.
    • Add compiler attribute to par_binary, to use a compiler other than the default.

    Notable fixes:

    • Par files are created with deterministic time stamps.
    Source code(tar.gz)
    Source code(zip)
  • 1.1.0(Nov 13, 2017)

    New features:

    • Allow pkg_resources' resource APIs to be used inside .par files. (#52)
    • Expose package metadata from wheels in .par files (#49)
    • Add par_test variant of par_binary (#36)

    Notable bug fixes:

    • Retain Bazel's ordering of Python import paths (#48)
    Source code(tar.gz)
    Source code(zip)
Owner
Google
Google ❤️ Open Source
Google
A tool used to obfuscate python scripts, bind obfuscated scripts to fixed machine or expire obfuscated scripts.

PyArmor Homepage (中文版网站) Documentation(中文版) PyArmor is a command line tool used to obfuscate python scripts, bind obfuscated scripts to fixed machine

Dashingsoft 1.9k Jan 01, 2023
An example of repository data as bundles

Bundles This repository is just an example of how we can host Git bundles in a way that supports fetching data from precomputed bundles without the or

Derrick Stolee 1 Jan 02, 2022
executable archive format

XAR XAR lets you package many files into a single self-contained executable file. This makes it easy to distribute and install. A .xar file is a read-

Facebook Incubator 1.5k Dec 29, 2022
debinstaller - A tool to install .deb files in any distro.

debinstaller A tool to install .deb files in any distro. Installation for debinstaller

Manoj Paramsetti 6 Nov 06, 2022
Psgcompiler A PySimpleGUI Application - Transform your Python programs in Windows, Mac, and Linux binary executables

psgcompiler A PySimpleGUI Application "Compile" your Python programs into an EXE for Windows, an APP for Mac, and a binary for Linux Installation Old-

PySimpleGUI 77 Jan 07, 2023
modified py2exe to support unicode paths

modified py2exe to support unicode paths

auto packaging for iOS

iOS Auto Packaging iOS自动打包脚本 准备 脚本第一次执行之前 先检查依赖, packaging目录下终端执行 pip3 install -r requirements.txt 运行 cd packaging packaging.py -h help -s scheme

DeeCo 17 Jul 23, 2022
FreezeUI is a python package that creates applications using cx_freeze and GUI by converting .py to .exe .

FreezeUI is a python package use to create cx_Freeze setup files and run them to create applications and msi from python scripts (converts .py to .exe or .msi .

4 Aug 25, 2022
Ninja is a small build system with a focus on speed.

Ninja Python Distributions Ninja is a small build system with a focus on speed. The latest Ninja python wheels provide ninja 1.10.2.g51db2.kitware.job

33 Dec 19, 2022
A modern Python application packaging and distribution tool

PyOxidizer PyOxidizer is a utility for producing binaries that embed Python. The over-arching goal of PyOxidizer is to make complex packaging and dist

Gregory Szorc 4.5k Jan 07, 2023
WinPython is a portable distribution of the Python programming language for Windows

WinPython tools Copyright © 2012-2013 Pierre Raybaut Copyright © 2014-2019+ The Winpython development team https://github.com/winpython/ Licensed unde

1.5k Jan 04, 2023
A distutils extension to create standalone Windows programs from Python code

py2exe for Python 3 py2exe is a distutils extension which allows to build standalone Windows executable programs (32-bit and 64-bit) from Python scrip

py2exe 526 Jan 04, 2023
py2app is a Python setuptools command which will allow you to make standalone Mac OS X application bundles and plugins from Python scripts.

py2app is a Python setuptools command which will allow you to make standalone Mac OS X application bundles and plugins from Python scripts. py2app is

Ronald Oussoren 222 Dec 30, 2022
Build Windows installers for Python applications

Pynsist is a tool to build Windows installers for your Python applications. The installers bundle Python itself, so you can distribute your applicatio

Thomas Kluyver 818 Jan 05, 2023
Subpar is a utility for creating self-contained python executables. It is designed to work well with Bazel.

Subpar Subpar is a utility for creating self-contained python executables. It is designed to work well with Bazel. Status Subpar is currently owned by

Google 550 Dec 27, 2022
Python Wheel Obfuscator

pywhlobf obfuscates your wheel distribution by compiling python source file to shared library.

Hunt Zhan 79 Dec 22, 2022
A library which implements low-level functions that relate to packaging and distribution of Python

What is it? Distlib is a library which implements low-level functions that relate to packaging and distribution of Python software. It is intended to

Python Packaging Authority 29 Oct 11, 2022
Nuitka Organization 8k Jan 07, 2023
tool for creating installers from conda packages

(conda) Constructor Description Constructor is a tool which allows constructing an installer for a collection of conda packages. It solves needed pack

Conda 386 Jan 04, 2023
Auto locust load test config and worker distribution with Docker and GitHub Action

Auto locust load test config and worker distribution with Docker and GitHub Action Install Fork the repo and change the visibility option to private S

Márk Zsibók 1 Nov 24, 2021