A utility that makes it easy to work with Python projects containing lots of packages, of which you only want to develop some.

Overview

Mixed development source packages on top of stable constraints using pip

mxdev [mɪks dɛv] is a utility that makes it easy to work with Python projects containing lots of packages, of which you only want to develop some.

It builds on top of the idea to have stable version constraints and then develop from a VCS on top of it.

Other software following the same idea are mr.developer for Python's zc.buildout or mrs-developer for NPM packages.

Overview

mxdev procedure is:

  1. Configuration is read,
  2. Requirements and constraints (given in configuration) are read.
  3. Sources from VCS are fetched into a target directory,
  4. Modified constraints (handled packages commented)/ requirements (handled packages as editable from sources) are written.

mxdev will not run pip for you!

Configuration

Given a requirements.txt (or similar named) file which itself references a constraints.txt file inside.

Create an INI file, like sources.ini in configparser.ExtendedInterpolation syntax.

The main section must be called [settings], even if kept empty. In the main sections the input and output files are defined.

requirements-in
Main requirements file to start with. This can be an URL too. Default: requirements.txt
requirements-out
Output of the combined requirements including development sources to be used later with pip install. Default: requirements-dev.txt
constraints-out
Output of the combined constraints. Default: constraints-dev.txt
target
Target directory for sources from VCS. Default: ./sources

Additional, custom variables can be defined as key = value pair. Those can be referenced in other values as ${settings:key} and will be expanded there.

Subsequent sections are defining the sources.

[PACKAGENAME]
The section name is the package name.
url = URL
the URL to the source in VCS and must follow the pip install editable format. Attention, this differs from the format one copies from Github/Gitlab, etc. The URL is required.
branch = BRANCHNAME_OR_TAG
the branch name or tag to checkout. Defaults to main.
extras = EXTRA1,EXTRA2
Package extras to install. Default empty.
subdirectory = SUBPATH
For specifying the path to the Python package, when it is not in the root of the VCS directory. Default empty.
target
Target directory for source from this section. Default to target directory configured in main section [settings] target = value.

Usage

Run mxdev -c sources.ini.

Now use the generated requirements and constrainst files with pip install -r NEW_REQUIREMENTS_FILENAME.txt.

Example Configuration

This looks like so:

[settings]
requirements-in = requirements-infile.txt
requirements-out = requirements-outfile.txt
contraints-out = constraints-outfile.txt

# custom variables
github = git+ssh://[email protected]/

[foo.bar]
url = ${settings:github}orga/foo.bar.git
branch = fix99
extras = test,baz

Rationale

Problem
There is a constraint file like -c constraints.txt with a package foo.bar with a version pin. Then it is not possible to install this package in a requirements file editable like -r requirements.txt with -e git+ssh://[email protected]/orga/foo.bar.git@fix-99.
Idea
A pre-processor fetches (as this can be an URL) and expands all -c SOMEOTHER_FILE_OR_URL and -r SOMEOTHER_FILE_OR_URL files into one, filtering out all packages given in a configuration file. For each of those packages a -e ... entry is generated instead and written to a new TARGET.txt. The configuration is written in a file sources.ini in ExtendedInterpolation INI syntax (YAML would be nice, but the package must have as less dependencies as possible to other packages).
Trivia
Mx (generally pronounced like mix [mɪks], or [məks] in the UK) is meant to be a gender-neutral alternative to the titles Mr. and Ms. but also associates with mix.
Comments
  • Read infiles: unexpected keyword argument 'package_keys'

    Read infiles: unexpected keyword argument 'package_keys'

    I wanted to try out the latest changes. I did that in plone.scale with this change in tox.ini:

     [testenv:plone60-py{37,38,39,310}]
     commands_pre =
    -    pip install mxdev
    +    pip install git+https://github.com/bluedynamics/mxdev.git@main
         mxdev -c sources-60.ini
         pip install --use-deprecated legacy-resolver -rrequirements-60-mxdev.txt
    

    I than ran the Plone 6 Python 3.8 env (avoiding issue #10 on Py 3.9+) and this failed:

    $ tox -e plone60-py38
    plone60-py38 create: /Users/maurits/community/plone-coredev/6.0/src/plone.scale/.tox/plone60-py38
    plone60-py38 run-test-pre: PYTHONHASHSEED='2339498946'
    plone60-py38 run-test-pre: commands[0] | pip install git+https://github.com/bluedynamics/mxdev.git@main
    Collecting git+https://github.com/bluedynamics/mxdev.git@main
      Cloning https://github.com/bluedynamics/mxdev.git (to revision main) to /private/var/folders/26/1plvhxbs6yx7g_82v2xdxc500000gn/T/pip-req-build-o7neug69
      Running command git clone --filter=blob:none --quiet https://github.com/bluedynamics/mxdev.git /private/var/folders/26/1plvhxbs6yx7g_82v2xdxc500000gn/T/pip-req-build-o7neug69
      Resolved https://github.com/bluedynamics/mxdev.git to commit 1d2d7aa0a7409120437c1d8e299690f31d0748d4
      Preparing metadata (setup.py) ... done
    Requirement already satisfied: setuptools in ./.tox/plone60-py38/lib/python3.8/site-packages (from mxdev==2.1.0.dev0) (62.0.0)
    Collecting libvcs>=0.10.1
      Using cached libvcs-0.11.1-py3-none-any.whl (16 kB)
    Building wheels for collected packages: mxdev
      Building wheel for mxdev (setup.py) ... done
      Created wheel for mxdev: filename=mxdev-2.1.0.dev0-py3-none-any.whl size=10013 sha256=971e2731fbb323b9324e1fce046824f7c0de1cea4bb4f405ba6d0c837e50c4a3
      Stored in directory: /private/var/folders/26/1plvhxbs6yx7g_82v2xdxc500000gn/T/pip-ephem-wheel-cache-ckwnrjvt/wheels/7f/2f/3a/540b397dc603c9eee3e0e25feaad96b9abbb0840cd2cfe59a9
    Successfully built mxdev
    Installing collected packages: libvcs, mxdev
    Successfully installed libvcs-0.11.1 mxdev-2.1.0.dev0
    plone60-py38 run-test-pre: commands[1] | mxdev -c sources-60.ini
    ###############################################################################
    # Load configuration
    Can not parse override: 
    ###############################################################################
    # Read infiles
    Read [r]: requirements-60.txt
    Traceback (most recent call last):
      File "/Users/maurits/community/plone-coredev/6.0/src/plone.scale/.tox/plone60-py38/bin/mxdev", line 8, in <module>
        sys.exit(main())
      File "/Users/maurits/community/plone-coredev/6.0/src/plone.scale/.tox/plone60-py38/lib/python3.8/site-packages/mxdev.py", line 416, in main
        read(state)
      File "/Users/maurits/community/plone-coredev/6.0/src/plone.scale/.tox/plone60-py38/lib/python3.8/site-packages/mxdev.py", line 259, in read
        process_io(
      File "/Users/maurits/community/plone-coredev/6.0/src/plone.scale/.tox/plone60-py38/lib/python3.8/site-packages/mxdev.py", line 233, in process_io
        new_requirements, new_constraints = process_line(
      File "/Users/maurits/community/plone-coredev/6.0/src/plone.scale/.tox/plone60-py38/lib/python3.8/site-packages/mxdev.py", line 192, in process_line
        return read(
    TypeError: read() got an unexpected keyword argument 'package_keys'
    ERROR: InvocationError for command /Users/maurits/community/plone-coredev/6.0/src/plone.scale/.tox/plone60-py38/bin/mxdev -c sources-60.ini (exited with code 1)
    _________________________________________________________________________________________________________________ summary __________________________________________________________________________________________________________________
    ERROR:   plone60-py38: commands failed
    

    Indeed the read method no longer accepts this keyword argument since PR #8.

    01 type: bug 
    opened by mauritsvanrees 3
  • Support git push URLs

    Support git push URLs

    Add a URL for pushing like with git remote set-url --push origin SOMEURL.

    In sources.ini this should look like:

    # ...
    [my.pkg]
    url = git+https://github.com/orga/repo
    push = git+ssh://[email protected]/orga/repo
    

    Easiest would be to add this feature to libvcs first and then use it. I opened a request https://github.com/vcs-python/libvcs/issues/297

    13 prio: normal 22 status: in-progress 04 type: enhancement 
    opened by jensens 3
  • Overwrite version doesn't work

    Overwrite version doesn't work

    I tried to overwrite the version of plone.restapi from Plone 6.0.0.b3 but it didn't work.

    My requirements.txt:

    -c https://dist.plone.org/release/6.0-latest/constraints.txt
    Plone
    

    My mx.ini:

    [settings]
    requirements-in = requirements.txt
    requirements-out = requirements-mxdev.txt
    
    version-overrides =
        plone.restapi==8.32.2
    

    I get the error:

    ERROR: Cannot install -r requirements-mxdev.txt (line 12) because these package versions have conflicting dependencies.
    
    The conflict is caused by:
        plone 6.0.0b3 depends on plone.restapi
        The user requested (constraint) plone-restapi==8.32.2
    
    To fix this you could try to:
    1. loosen the range of package versions you've specified
    2. remove package versions to allow pip attempt to solve the dependency conflict
    
    ERROR: ResolutionImpossible: for help visit https://pip.pypa.io/en/latest/topics/dependency-resolution/#dealing-with-dependency-conflicts
    
    opened by wesleybl 2
  • Version pinning of dependency of checked out package

    Version pinning of dependency of checked out package

    I checkout package A. Package A has a dependency B. Package A pins B to version v.y Plone has a constraint on B to version v.x. This is a conflict. "make install" fails with [^version-conflict], which is what I expect. I can solve the conflict by pinning B in sources.ini 'version-overrides'. But, is this the recommended place to pin? Can I force to fullfill any constraints of A somehow in sources.ini?

    [^version-conflict]: Version conflict ``` INFO: pip is looking at multiple versions of plone-restapi[test] to determine which version is compatible with other requirements. This could take a while. ERROR: Cannot install plone-api[test]==2.0.0a4.dev0 because these package versions have conflicting dependencies.

    The conflict is caused by:
        plone-api[test] 2.0.0a4.dev0 depends on manuel>=1.11.2; extra == "test"
        The user requested (constraint) manuel==1.10.1
    
    To fix this you could try to:
    1. loosen the range of package versions you've specified
    2. remove package versions to allow pip attempt to solve the dependency conflict
    
    ERROR: ResolutionImpossible: for help visit https://pip.pypa.io/en/latest/topics/dependency-resolution/#dealing-with-dependency-conflicts
    make: *** [.sentinels/install.sentinel] Error 1
    
    
    ```
    
    05 type: question 33 needs: docs 
    opened by ksuess 2
  • refactored shortcut create_repo -> create_project

    refactored shortcut create_repo -> create_project

    https://github.com/vcs-python/libvcs/commit/b309633dcadaffcaea512ffaae93a839d81c99d0

    since libvcs >= 0.12.0 the shortcuts are refactored and only compatible with python>=3.9

    opened by petschki 2
  • interdependency mode broken

    interdependency mode broken

    The interdependency mode hack seems broken. This might be a side effect of the legacy resolver. But: Using pip https://github.com/pypa/pip main branch the legacy resolver and the interdependency hack is no longer needed

    Possible solution:

    • depend on 22.0 as soon as it is released.
    • remove interdependency mode hack at all.
    • alias modes direct and interdependency to install
    • deprecate modes direct and interdependency
    opened by jensens 1
  • Re-run of pip vanishes comitted changes

    Re-run of pip vanishes comitted changes

    pip -e GITURL drops all changes done local (non-pushed) with

    Obtaining collective.richdescription from git+ssh://****@github.com/collective/collective.richdescription.git@main#egg=collective.richdescription (from -r requirements-dev.txt (line 29))
      Updating ./devsrc/collective-richdescription clone (to revision main)
      Running command git fetch -q --tags
      Running command git reset --hard -q 20cc5a1b98dfe2bf2ef6e46735279861fb92ecf1
      Preparing metadata (setup.py) ... done
    

    This is a problem.

    opened by jensens 1
  • Need a flag for checking out git submodules

    Need a flag for checking out git submodules

    libvcs checked out git repos with --recurse-submodules by default. We need either to add this flag by default or add an option in mx.ini controlling this behavior

    02 type: regression 
    opened by rnixx 0
  • Incompatible with libvcs 0.12

    Incompatible with libvcs 0.12

    In the plone.scale repo we use mxdev. This currently works on Python 3.8 and lower, but fails on 3.9 and 3.10 because pip then pulls in a newer libvcs which fails for us:

    $ tox -e plone60-py39
    plone60-py39 create: /Users/maurits/community/plone-coredev/6.0/src/plone.scale/.tox/plone60-py39
    plone60-py39 run-test-pre: PYTHONHASHSEED='3997488647'
    plone60-py39 run-test-pre: commands[0] | pip install mxdev
    Collecting mxdev
      Using cached mxdev-2.0.0-py3-none-any.whl (8.6 kB)
    Requirement already satisfied: setuptools in ./.tox/plone60-py39/lib/python3.9/site-packages (from mxdev) (62.0.0)
    Collecting libvcs>=0.10.1
      Using cached libvcs-0.12.0-py3-none-any.whl (34 kB)
    Installing collected packages: libvcs, mxdev
    Successfully installed libvcs-0.12.0 mxdev-2.0.0
    plone60-py39 run-test-pre: commands[1] | mxdev -c sources-60.ini
    Traceback (most recent call last):
      File "/Users/maurits/community/plone-coredev/6.0/src/plone.scale/.tox/plone60-py39/bin/mxdev", line 5, in <module>
        from mxdev import main
      File "/Users/maurits/community/plone-coredev/6.0/src/plone.scale/.tox/plone60-py39/lib/python3.9/site-packages/mxdev.py", line 2, in <module>
        from libvcs.shortcuts import create_repo_from_pip_url
    ImportError: cannot import name 'create_repo_from_pip_url' from 'libvcs.shortcuts' (/Users/maurits/community/plone-coredev/6.0/src/plone.scale/.tox/plone60-py39/lib/python3.9/site-packages/libvcs/shortcuts.py)
    ERROR: InvocationError for command /Users/maurits/community/plone-coredev/6.0/src/plone.scale/.tox/plone60-py39/bin/mxdev -c sources-60.ini (exited with code 1)
    _________________________________________________________________________________________________________________ summary __________________________________________________________________________________________________________________
    ERROR:   plone60-py39: commands failed
    

    I have a fix ready. Not sure how to try that out, but I will make a PR.

    opened by mauritsvanrees 0
  • Wrong path to constraints in requirements-out file

    Wrong path to constraints in requirements-out file

    I'm using mxdev with this configuration:

    [settings]
    requirements-in = requirements/plone.in
    requirements-out = requirements/plone.txt
    constraints-out = requirements/constraints.txt
    default-target = src
    version-overrides =
    

    requirements/plone.in contains:

    -c https://dist.plone.org/release/6.0.0b3/constraints.txt
    Plone
    

    After I run mxdev, it generates requirements/constraints.txt and requirements/plone.txt, but requirements/plone.txt has the wrong relative path to the constraints file:

    ###############################################################################
    # mxdev combined constraints
    -c requirements/constraints.txt
    
    ###############################################################################
    # begin requirements from: plone.in
    
    Plone
    
    # end requirements from: plone.in
    ###############################################################################
    

    (It should be -c constraints.txt)

    Then that breaks when I try to pip install -r requirements/plone.txt: ERROR: Could not open requirements file: [Errno 2] No such file or directory: 'requirements/requirements/constraints.txt'

    13 prio: normal 01 type: bug 21 status: confirmed 
    opened by davisagli 1
Owner
BlueDynamics Alliance
BlueDynamics Alliance
A work in progress box containing various Python utilities

python-wipbox A set of modern Python libraries under development to simplify the execution of reusable routines by different projects. Table of Conten

Deepnox 2 Jan 20, 2022
A python package containing all the basic functions and classes for python. From simple addition to advanced file encryption.

A python package containing all the basic functions and classes for python. From simple addition to advanced file encryption.

PyBash 11 May 22, 2022
SysInfo is an app developed in python which gives Basic System Info , and some detailed graphs of system performance .

SysInfo SysInfo is an app developed in python which gives Basic System Info , and some detailed graphs of system performance . Installation Download t

null 5 Nov 8, 2021
pydsinternals - A Python native library containing necessary classes, functions and structures to interact with Windows Active Directory.

pydsinternals - Directory Services Internals Library A Python native library containing necessary classes, functions and structures to interact with W

Podalirius 36 Dec 14, 2022
A repository containing several general purpose Python scripts to automate daily and common tasks.

General Purpose Scripts Introduction This repository holds a curated list of Python scripts which aim to help us automate daily and common tasks. You

GDSC RCCIIT 46 Dec 25, 2022
This is Cool Utility tools that you can use in python.

This is Cool Utility tools that you can use in python. There are a few tools that you might find very useful, you can use this on pretty much any project and some utils might help you a lot and save so much time since it’s a simple function.

Senarc Studios 6 Apr 18, 2022
Python program for Linux users to change any url to any domain name they want.

URLMask Python program for Linux users to change a URL to ANY domain. A program than can take any url and mask it to any domain name you like. E.g. ne

null 2 Jun 20, 2022
A small python library that helps you to generate localization strings for your mobile projects.

LocalizationUtiltiy A small python library that helps you to generate localization strings for your mobile projects. This small script aims to help yo

null 1 Nov 12, 2021
This utility lets you draw using your laptop's touchpad on Linux.

FingerPaint This utility lets you draw using your laptop's touchpad on Linux. Pressing any key or clicking the touchpad will finish the drawing

Wazzaps 95 Dec 17, 2022
Helper script to bootstrap a Python environment with the tools required to build and install packages.

python-bootstrap Helper script to bootstrap a Python environment with the tools required to build and install packages. Usage $ python -m bootstrap.bu

Filipe Laíns 7 Oct 6, 2022
Shut is an opinionated tool to simplify publishing pure Python packages.

Welcome to Shut Shut is an opinionated tool to simplify publishing pure Python packages. What can Shut do for you? Generate setup files (setup.py, MAN

Niklas Rosenstein 6 Nov 18, 2022
Aurin - A quick AUR installer for Arch Linux. Install packages from AUR website in a click.

Aurin - A quick AUR installer for Arch Linux. Install packages from AUR website in a click.

Suleman 51 Nov 4, 2022
This tool lets you perform some quick tasks for CTFs and Pentesting.

This tool lets you convert strings and numbers between number bases (2, 8, 10 and 16) as well as ASCII text. You can use the IP address analyzer to find out details on IPv4 and perform abbreviation as well as expansion on IPv6 addresses.It can also perform a two's complement calculation as well.

Ayomide Ayodele-Soyebo 1 Jul 16, 2022
A clock app, which helps you with routine tasks.

Clock This app helps you with routine tasks. Alarm Clock Timer Stop Watch World Time (Which city you want) About me Full name: Matin Ardestani Age: 14

Matin Ardestani 13 Jul 30, 2022
isort is a Python utility / library to sort imports alphabetically, and automatically separated into sections and by type.

isort is a Python utility / library to sort imports alphabetically, and automatically separated into sections and by type. It provides a command line utility, Python library and plugins for various editors to quickly sort all your imports.

Python Code Quality Authority 5.5k Jan 8, 2023
Python utility for discovering interesting CFPreferences values on iDevices

Description Simple utility to search for interesting preferences in iDevices. Installation python3 -m pip install -U --user cfprefsmon Example In this

null 12 Aug 19, 2022
Yet another retry utility in Python

Yet another retry utility in Python, avereno being the Malagasy word for retry.

Haute École d'Informatique de Madagascar 4 Nov 2, 2021
The git for the Python Story Utility Package library.

SUP The git for the Python Story Utility Package library. Installation: Install SUP by simply running pip install psup in your terminal. Check out our

Enoki 6 Nov 27, 2022
A collection of utility functions to prototype geometry processing research in python

gpytoolbox This repo is a work in progress and contains general utility functions I have needed to code while trying to work on geometry process resea

Silvia Sellán 73 Jan 6, 2023