Skip to content

Instantly share code, notes, and snippets.

@michaelaye
Forked from michael-ford/conda_env_export.py
Created October 22, 2021 23:28
Show Gist options
  • Select an option

  • Save michaelaye/454c2264bfb84c76634ee2bd72d551f7 to your computer and use it in GitHub Desktop.

Select an option

Save michaelaye/454c2264bfb84c76634ee2bd72d551f7 to your computer and use it in GitHub Desktop.

Revisions

  1. @gwerbin gwerbin created this gist Jan 8, 2021.
    79 changes: 79 additions & 0 deletions conda_env_export.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,79 @@
    """
    Export a Conda environment with --from-history, but also append
    Pip-installed dependencies
    Exports only manually-installed dependencies, excluding build versions, but
    including Pip-installed dependencies.
    Lots of issues requesting this functionality in the Conda issue tracker, no
    sign of progress (as of March 2020).
    TODO (?): support command-line flags -n and -p
    """
    import re
    import subprocess
    import sys

    import yaml


    def export_env(history_only=False, include_builds=False):
    """ Capture `conda env export` output """
    cmd = ['conda', 'env', 'export']
    if history_only:
    cmd.append('--from-history')
    if include_builds:
    raise ValueError('Cannot include build versions with "from history" mode')
    if not include_builds:
    cmd.append('--no-builds')
    cp = subprocess.run(cmd, stdout=subprocess.PIPE)
    try:
    cp.check_returncode()
    except Exception as e:
    raise e
    else:
    return yaml.safe_load(cp.stdout)


    def _is_history_dep(d, history_deps):
    if not isinstance(d, str):
    return False
    d_prefix = re.sub(r'=.*', '', d)
    return d_prefix in history_deps


    def _get_pip_deps(full_deps):
    for dep in full_deps:
    if isinstance(dep, dict) and 'pip' in dep:
    return dep


    def _combine_env_data(env_data_full, env_data_hist):
    deps_full = env_data_full['dependencies']
    deps_hist = (env_data_hist['dependencies'])
    deps = [dep for dep in deps_full if _is_history_dep(dep, deps_hist)]

    pip_deps = _get_pip_deps(deps_full)

    env_data = {}
    env_data['channels'] = env_data_full['channels']
    env_data['dependencies'] = deps
    env_data['dependencies'].append(pip_deps)

    return env_data


    def main():
    env_data_full = export_env()
    env_data_hist = export_env(history_only=True)
    env_data = _combine_env_data(env_data_full, env_data_hist)
    yaml.dump(env_data, sys.stdout)
    print('Warning: this output might contain packages installed from non-public sources, e.g. a Git repository. '
    'You should review and test the output to make sure it works with `conda env create -f`, '
    'and make changes as required.\n'
    'For example, `conda-env-export` itself is not currently uploaded to PyPI, and it must be removed from '
    'the output file, or else `conda create -f` will fail.', file=sys.stderr)


    if __name__ == '__main__':
    main()
    1 change: 1 addition & 0 deletions requirements.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    pyyaml