Use CloudRepo’s PyPI index from Conda

This section provides comprehensive documentation for using CloudRepo with Conda and Miniconda, the package and environment management systems widely used in data science, machine learning, and scientific computing.

See also

Authenticate with a repository token. Repository Tokens: Create One and Authenticate shows how to create one, with a ready-to-paste example. For conda: the username is the email address of the account that created the token, in lower case, and the password is the token.

Introduction to Conda

What is Conda?

Conda is a powerful, open-source package and environment management system that runs on Windows, macOS, and Linux. Originally developed for Python programs, Conda has evolved into a language-agnostic package manager that can install and manage packages from any language. Miniconda is a minimal installer that includes only Conda, Python, and their dependencies, providing a lightweight starting point for creating custom environments.

Conda’s Role in Scientific Python and Data Science

Conda has become the de facto standard in scientific computing and data science for several compelling reasons:

  • Binary package management: Unlike pip which primarily handles pure Python packages, Conda excels at managing complex binary dependencies including C/C++ libraries, CUDA toolkits, and system-level packages

  • Cross-language support: Seamlessly manages packages from Python, R, Julia, Scala, Java, JavaScript, C/C++, FORTRAN, and more

  • Environment isolation: Creates truly isolated environments with their own Python interpreters and system libraries

  • Reproducible science: Enables exact environment replication across different machines and operating systems

  • Optimized packages: Conda-forge and defaults channels provide pre-compiled, optimized binaries for scientific libraries like NumPy, SciPy, and TensorFlow

  • Dependency solver: Advanced SAT solver handles complex dependency graphs that often challenge pip

Why Teams Need Private Package Management

Data science and research teams increasingly require private package management for:

  • Proprietary algorithms: Protecting intellectual property in custom ML models and analysis tools

  • Internal libraries: Sharing data processing pipelines, feature engineering tools, and domain-specific utilities

  • Compliance and security: Maintaining control over package distribution in regulated industries (healthcare, finance, government)

  • Version control: Ensuring reproducibility of experiments and analyses across team members

  • Performance optimization: Distributing custom-compiled packages optimized for specific hardware

  • Data connectors: Securely sharing database connectors and API clients with embedded credentials

CloudRepo’s Conda Strategy

CloudRepo does not host conda packages or serve a conda channel. It hosts Python packages in a PyPI index, and a conda user installs them with pip inside the conda environment.

PyPI Integration

CloudRepo fully supports Python packages that can be installed in Conda environments using pip. This covers the majority of custom Python packages that data science teams develop, including pure Python libraries, data processing tools, and ML model packages.

Conda packages stay on their channels

Conda packages, such as compiled libraries with complex binary dependencies, install from conda-forge, defaults or a channel you host yourself, as before.

Prerequisites

Before configuring Conda to work with CloudRepo, ensure you have:

  1. CloudRepo Account and Repository

    • An active CloudRepo organization account

    • A Python repository created in the CloudRepo Admin Portal

    • A repository user with appropriate permissions (read for downloading, write for uploading)

    Note

    Your admin user cannot access repositories directly for security reasons. Always create dedicated repository users in the CloudRepo Admin Portal.

    For setup instructions, see:

  2. Conda or Miniconda Installation

    • Conda (via Anaconda) or Miniconda installed on your system

    • Verify installation: conda --version

  3. Repository URL Format

    Your CloudRepo PyPI repository URL follows this pattern:

    https://[organization-id].mycloudrepo.io/repositories/[repository-id]/simple
    

    You can find the exact URL in the CloudRepo Admin Portal under your repository’s settings.

Using CloudRepo with Conda for PyPI Packages

Configuring pip within Conda Environments

CloudRepo integrates with Conda environments through pip. Install your private packages from CloudRepo alone, in a pip step of their own: anyone can publish a package on PyPI under your private package’s name, and a pip step that can also read PyPI may install theirs instead (see Installing Private and Public Packages Together).

Public packages from PyPI, private packages from CloudRepo alone
# Create and activate a new environment
conda create -n myproject python=3.11 pip
conda activate myproject

# Public packages: from PyPI, pip's default index
pip install -r requirements.txt

# Private packages: from CloudRepo alone (requirements-private.txt names its index,
# and pip reads the login for the host from ~/.netrc, set up under Authentication Setup)
pip install -r requirements-private.txt
requirements-private.txt
--index-url https://[org-id].mycloudrepo.io/repositories/[repo-id]/simple
acme-ml-core==3.2.1
acme-feature-pipeline==2.0.0

pip reads the login for the host from ~/.netrc (see Authentication Setup below), so requirements-private.txt holds no credential and can be committed. Its --index-url line makes CloudRepo the only index for that command. List the public packages your private packages depend on in requirements.txt or environment.yml: the CloudRepo step does not look for them on PyPI, and fails if one is missing. Nothing in requirements.txt may depend on a private package, your own project included, or pip fetches that package from PyPI; install your project last with pip install --no-deps -e .. If an earlier setup put CloudRepo and PyPI together in pip.conf, pip config or PIP_EXTRA_INDEX_URL, remove that, because every pip install reads such a pair as one index.

Mixing Conda-Forge and Private PyPI Packages

Data science projects often require packages from both conda-forge (for optimized binaries) and private PyPI repositories (for proprietary code). conda runs one pip install for the whole pip: section of environment.yml, so keep that section for public packages and install your private packages in a second step:

environment.yml - Mixed conda and pip dependencies
 1name: data-science-project
 2channels:
 3  - conda-forge
 4  - defaults
 5dependencies:
 6  # Conda packages for optimized binaries
 7  - python=3.11
 8  - numpy=1.24.*
 9  - pandas=2.0.*
10  - scikit-learn=1.3.*
11  - matplotlib=3.7.*
12  - jupyter=1.0.*
13  - pytorch=2.0.*
14  - cudatoolkit=11.8  # For GPU support
15
16  # Public packages better installed via pip, from PyPI. No CloudRepo index
17  # or token here: the private packages come from requirements-private.txt.
18  - pip
19  - pip:
20    - transformers==4.30.0
21    - langchain==0.0.200
requirements-private.txt - Private packages, from CloudRepo alone
--index-url https://[org-id].mycloudrepo.io/repositories/[repo-id]/simple
acme-ml-library==2.1.0
acme-data-connectors==1.5.3
acme-feature-engine==3.0.1
Creating environment from YAML file
# Create environment from file: conda packages, then the public pip packages
conda env create -f environment.yml

# Activate environment
conda activate data-science-project

# Install the private packages from CloudRepo alone; pip reads the
# login for the host from ~/.netrc
pip install -r requirements-private.txt

# Verify private packages installed
pip list | grep acme-

Authentication Setup

CloudRepo supports multiple authentication methods for different scenarios:

Secure Credential Storage with keyring

Using keyring for secure credential storage
# Install keyring in your conda environment
conda activate myproject
pip install keyring

# Store credentials securely
keyring set https://[org-id].mycloudrepo.io/repositories/[repo-id]/simple you@example.com
# Paste your repository token when prompted

# Configure pip to use keyring
pip config set global.index-url https://[org-id].mycloudrepo.io/repositories/[repo-id]/simple

Using .netrc for Authentication

~/.netrc file configuration
machine [org-id].mycloudrepo.io
login you@example.com
password YOUR_REPOSITORY_TOKEN
Secure the .netrc file
chmod 600 ~/.netrc

Environment Variables for CI/CD

CI/CD authentication using environment variables
# Set in your CI/CD system's secret management
export CLOUDREPO_USERNAME=you@example.com
export CLOUDREPO_API_TOKEN=YOUR_REPOSITORY_TOKEN

# Write the ~/.netrc entry from them; pip reads the login for the host from it
(umask 077 && printf 'machine [org-id].mycloudrepo.io\nlogin %s\npassword %s\n' \
  "$CLOUDREPO_USERNAME" "$CLOUDREPO_API_TOKEN" >> ~/.netrc)

# The index URL carries no credential
pip install --index-url https://[org-id].mycloudrepo.io/repositories/[repo-id]/simple your-package

Publishing Python Packages for Conda Users

Building Conda-Compatible Wheels

When publishing Python packages for Conda users, ensure compatibility by following these best practices:

setup.py - Conda-compatible package configuration
 1from setuptools import setup, find_packages
 2import sys
 3
 4# Detect if running in conda environment
 5is_conda = sys.prefix != sys.base_prefix or 'conda' in sys.prefix
 6
 7setup(
 8    name='your-data-science-library',
 9    version='1.0.0',
10    packages=find_packages(),
11    python_requires='>=3.8,<3.12',
12    install_requires=[
13        'numpy>=1.20,<2.0',
14        'pandas>=1.3,<3.0',
15        'scikit-learn>=1.0',
16    ],
17    extras_require={
18        'viz': ['matplotlib>=3.5', 'seaborn>=0.12'],
19        'gpu': ['cupy>=10.0'],
20        'dev': ['pytest>=7.0', 'black>=22.0', 'mypy>=1.0'],
21    },
22    # Metadata
23    author='Your Team',
24    author_email='team@company.com',
25    description='Internal data science utilities',
26    long_description=open('README.md').read(),
27    long_description_content_type='text/markdown',
28    classifiers=[
29        'Development Status :: 4 - Beta',
30        'Intended Audience :: Science/Research',
31        'Programming Language :: Python :: 3.8',
32        'Programming Language :: Python :: 3.9',
33        'Programming Language :: Python :: 3.10',
34        'Programming Language :: Python :: 3.11',
35    ],
36)
pyproject.toml - Modern Python packaging
 1[build-system]
 2requires = ["setuptools>=61.0", "wheel"]
 3build-backend = "setuptools.build_meta"
 4
 5[project]
 6name = "your-data-science-library"
 7version = "1.0.0"
 8description = "Internal data science utilities"
 9readme = "README.md"
10requires-python = ">=3.8,<3.12"
11dependencies = [
12    "numpy>=1.20,<2.0",
13    "pandas>=1.3,<3.0",
14    "scikit-learn>=1.0",
15]
16
17[project.optional-dependencies]
18viz = ["matplotlib>=3.5", "seaborn>=0.12"]
19gpu = ["cupy>=10.0"]
20dev = ["pytest>=7.0", "black>=22.0", "mypy>=1.0"]
21
22[tool.setuptools.packages.find]
23include = ["your_package*"]

Publishing to CloudRepo’s PyPI Index

Upload your packages to CloudRepo using standard Python packaging tools:

Building and publishing with build and twine
# Install build tools in conda environment
conda activate myproject
pip install build twine

# Build your package
python -m build

# Upload to CloudRepo. twine reads its credential from these two variables
export TWINE_USERNAME=you@example.com
export TWINE_PASSWORD=YOUR_REPOSITORY_TOKEN
twine upload --non-interactive \
  --repository-url https://[org-id].mycloudrepo.io/repositories/[repo-id] \
  dist/*

Version Management for Data Science Packages

Data science packages often require careful version management due to model compatibility:

Semantic versioning for ML models
 1# your_package/__version__.py
 2__version__ = "2.1.0"
 3
 4# Version components:
 5# MAJOR.MINOR.PATCH
 6# 2 - Major model architecture changes
 7# 1 - New features, backward compatible
 8# 0 - Bug fixes, performance improvements
 9
10# Model versioning
11MODEL_VERSION = "2.1"  # Tracks trained model compatibility
12API_VERSION = "v2"     # Tracks API compatibility
Publishing pre-release versions for testing
# Beta releases for team testing
python setup.py sdist bdist_wheel
# Creates: your-package-2.1.0b1-py3-none-any.whl

# Upload beta to CloudRepo
twine upload --repository-url https://[org-id].mycloudrepo.io/repositories/[repo-id] dist/*2.1.0b1*

# Install beta version explicitly
pip install your-package==2.1.0b1

Platform-Specific Packages

Data science teams often need platform-specific builds for performance:

.github/workflows/build-wheels.yml - Multi-platform builds
 1name: Build and Publish Platform Wheels
 2
 3on:
 4  push:
 5    tags:
 6      - 'v*'
 7
 8jobs:
 9  build_wheels:
10    strategy:
11      matrix:
12        os: [ubuntu-latest, windows-latest, macos-latest]
13        python-version: ['3.8', '3.9', '3.10', '3.11']
14
15    runs-on: ${{ matrix.os }}
16
17    steps:
18      - uses: actions/checkout@v3
19
20      - uses: conda-incubator/setup-miniconda@v2
21        with:
22          python-version: ${{ matrix.python-version }}
23          activate-environment: build-env
24
25      - name: Install dependencies
26        run: |
27          conda install -c conda-forge numpy cython
28          pip install build twine
29
30      - name: Build platform wheel
31        run: python -m build --wheel
32
33      - name: Upload to CloudRepo
34        env:
35          TWINE_USERNAME: ${{ secrets.CLOUDREPO_USER }}
36          TWINE_PASSWORD: ${{ secrets.CLOUDREPO_API_TOKEN }}
37        run: |
38          twine upload --non-interactive \
39            --repository-url https://[org-id].mycloudrepo.io/repositories/[repo-id] \
40            dist/*.whl

Conda Environment Management with CloudRepo

Environment.yml with pip Dependencies from CloudRepo

Create reproducible environments that combine conda and CloudRepo packages:

Full data science environment with CloudRepo packages
 1name: ml-pipeline-prod
 2channels:
 3  - conda-forge
 4  - pytorch
 5  - nvidia
 6dependencies:
 7  # Core scientific stack
 8  - python=3.10.*
 9  - numpy=1.24.*
10  - pandas=2.0.*
11  - scipy=1.10.*
12
13  # Machine Learning
14  - scikit-learn=1.3.*
15  - xgboost=1.7.*
16  - lightgbm=4.0.*
17  - pytorch=2.0.*
18  - pytorch-cuda=11.8.*
19
20  # Deep Learning
21  - tensorflow=2.12.*
22  - keras=2.12.*
23
24  # Data Visualization
25  - matplotlib=3.7.*
26  - seaborn=0.12.*
27  - plotly=5.14.*
28  - bokeh=3.1.*
29
30  # Jupyter Ecosystem
31  - jupyter=1.0.*
32  - jupyterlab=4.0.*
33  - ipywidgets=8.0.*
34  - nbconvert=7.4.*
35
36  # Development Tools
37  - black=23.3.*
38  - pylint=2.17.*
39  - pytest=7.3.*
40  - pytest-cov=4.1.*
41
42  # Public packages from PyPI. The internal packages are not listed here:
43  # they come from requirements-private.txt, below.
44  - pip
45  - pip:
46    - mlflow==2.3.0
47    - wandb==0.15.0
48    - dvc==3.0.0
49
50# Environment variables
51variables:
52  PYTHONPATH: /opt/custom/libs:$PYTHONPATH
53  CUDA_HOME: /usr/local/cuda-11.8

Install the internal packages after conda env create, with pip install -r requirements-private.txt (see Mixing Conda-Forge and Private PyPI Packages). The file names CloudRepo as its only index and holds no token, so this environment.yml and this file are both safe to commit or copy into an image:

requirements-private.txt - ml-pipeline-prod internal packages
--index-url https://[org-id].mycloudrepo.io/repositories/[repo-id]/simple
acme-ml-core==3.2.1
acme-feature-pipeline==2.0.0
acme-model-registry-client==1.5.0
acme-data-quality-tools==1.1.0

Reproducible Environments

Ensure perfect reproducibility across team members and deployments:

Creating exact environment snapshots
# Export current environment with exact versions
conda list --explicit > conda-packages.txt
pip freeze > pip-packages.txt

# Create combined lock file
conda env export --no-builds > environment-lock.yml
environment-lock.yml - Pinned versions
 1name: ml-pipeline-prod
 2channels:
 3  - conda-forge
 4  - pytorch
 5dependencies:
 6  - python=3.10.11
 7  - numpy=1.24.3
 8  - pandas=2.0.2
 9  - pytorch=2.0.1
10  - pip:
11    - mlflow==2.3.0
12    - wandb==0.15.0
13    - dvc==3.0.0

conda env export also lists your private packages under pip:, with no index. Move them to requirements-private.txt before you commit the lock file: left in the pip: section, they are looked up on PyPI the next time the environment is created.

Mixing Conda and pip Packages

Best practices for combining conda and pip packages:

check_environment.py - Validate mixed environments
 1#!/usr/bin/env python
 2"""Verify conda/pip environment setup."""
 3
 4import sys
 5import importlib
 6import subprocess
 7from pathlib import Path
 8
 9def check_conda_packages():
10    """Verify conda-installed packages."""
11    required_conda = ['numpy', 'pandas', 'scipy', 'sklearn']
12
13    result = subprocess.run(['conda', 'list'],
14                           capture_output=True, text=True)
15    conda_packages = result.stdout
16
17    missing = []
18    for pkg in required_conda:
19        if pkg not in conda_packages:
20            missing.append(pkg)
21
22    return missing
23
24def check_pip_packages():
25    """Verify pip-installed CloudRepo packages."""
26    required_pip = {
27        'acme_ml_core': '3.2.1',
28        'acme_feature_pipeline': '2.0.0',
29    }
30
31    missing = []
32    wrong_version = []
33
34    for pkg, required_version in required_pip.items():
35        try:
36            module = importlib.import_module(pkg)
37            if hasattr(module, '__version__'):
38                if module.__version__ != required_version:
39                    wrong_version.append(f"{pkg} (found: {module.__version__}, required: {required_version})")
40        except ImportError:
41            missing.append(pkg)
42
43    return missing, wrong_version
44
45def main():
46    print("Checking environment setup...")
47
48    # Check conda packages
49    missing_conda = check_conda_packages()
50    if missing_conda:
51        print(f"❌ Missing conda packages: {', '.join(missing_conda)}")
52        print("   Run: conda install " + ' '.join(missing_conda))
53    else:
54        print("✅ All conda packages installed")
55
56    # Check pip packages
57    missing_pip, wrong_version = check_pip_packages()
58    if missing_pip:
59        print(f"❌ Missing CloudRepo packages: {', '.join(missing_pip)}")
60    if wrong_version:
61        print(f"❌ Wrong versions: {', '.join(wrong_version)}")
62
63    if not missing_pip and not wrong_version:
64        print("✅ All CloudRepo packages correctly installed")
65
66    # Check Python version
67    python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
68    print(f"📊 Python version: {python_version}")
69
70    return len(missing_conda) + len(missing_pip) + len(wrong_version)
71
72if __name__ == "__main__":
73    sys.exit(main())

Lock Files with conda-lock

Use conda-lock for advanced dependency locking across platforms:

Installing and using conda-lock
# Install conda-lock
conda install -c conda-forge conda-lock

# Generate lock file from environment.yml
conda-lock lock --file environment.yml --platform linux-64 --platform osx-64 --platform win-64
conda-lock.yml - Multi-platform lock file
 1# Generated by conda-lock
 2version: 1
 3metadata:
 4  content_hash:
 5    linux-64: abc123...
 6    osx-64: def456...
 7    win-64: ghi789...
 8  channels:
 9    - conda-forge
10    - pytorch
11  platforms:
12    - linux-64
13    - osx-64
14    - win-64
15package:
16  - name: python
17    version: 3.10.11
18    manager: conda
19    platform: linux-64
20    url: https://conda.anaconda.org/conda-forge/linux-64/python-3.10.11-h7a1cb2a_2.tar.bz2
21    hash:
22      md5: abc123...
23  - name: acme-ml-core
24    version: 3.2.1
25    manager: pip
26    url: https://[org-id].mycloudrepo.io/repositories/[repo-id]/simple
Creating environments from lock files
# Install from conda-lock file
conda-lock install --name ml-pipeline-prod conda-lock.yml

# Or render to platform-specific file
conda-lock render --platform linux-64
conda env create --file conda-linux-64.lock.yml

Advanced Topics

Using Mamba for Faster Dependency Resolution

Mamba is a drop-in replacement for conda with 10-100x faster dependency resolution:

Installing and using mamba
# Install mamba in base environment
conda install -n base -c conda-forge mamba

# Use mamba instead of conda
mamba env create -f environment.yml
mamba activate ml-pipeline-prod

# Mamba handles complex dependencies much faster
mamba install pytorch torchvision torchaudio pytorch-cuda=11.8 -c pytorch -c nvidia
.mambarc - Mamba configuration
channels:
  - conda-forge
  - pytorch
  - nvidia
channel_priority: strict
pip_interop_enabled: true

This file holds no pip index: pip_args is not a conda setting (conda config --set pip_args answers unknown parameter). Install private packages with requirements-private.txt, as in Mixing Conda-Forge and Private PyPI Packages.

Docker Containers with Conda and CloudRepo

Create reproducible Docker containers for deployment. Pass the CloudRepo username and token as build secrets, never as build arguments: Docker records build arguments in the image, where anyone who can pull it can read them. See Installing Packages from CloudRepo in a Docker Build for why.

The environment.yml this image copies must hold no CloudRepo URL or token, because COPY saves the file in the image. The one under Environment.yml with pip Dependencies from CloudRepo lists public packages only, so you can copy it as it is. Your private packages come from the one step that holds the secrets, and that step reads CloudRepo and nothing else (see Mixing Conda-Forge and Private PyPI Packages). That step does not look on PyPI, so the public packages your private packages depend on must be in environment.yml; if one is missing, the step fails.

Dockerfile - Conda with CloudRepo packages
 1# syntax=docker/dockerfile:1
 2# conda-forge's image: continuumio/miniconda3 is deprecated
 3FROM condaforge/miniforge3:latest
 4
 5# Set working directory
 6WORKDIR /app
 7
 8# Copy environment file: public packages only, no CloudRepo URL or token
 9COPY environment.yml .
10
11# Create conda environment
12RUN conda env create -f environment.yml && \
13    conda clean -afy && \
14    find /opt/conda/ -follow -type f -name '*.a' -delete && \
15    find /opt/conda/ -follow -type f -name '*.pyc' -delete && \
16    find /opt/conda/ -follow -type f -name '*.js.map' -delete
17
18# Activate environment by default
19SHELL ["conda", "run", "-n", "ml-pipeline-prod", "/bin/bash", "-c"]
20
21# Install your private packages from CloudRepo, and only from CloudRepo.
22# The login is a build secret: a netrc file that holds only the CloudRepo
23# entry, mounted for this step. pip reads the login for the host from it.
24RUN --mount=type=secret,id=netrc,target=/root/.netrc \
25    pip install \
26    --index-url https://[org-id].mycloudrepo.io/repositories/[repo-id]/simple \
27    acme-ml-core==3.2.1 \
28    acme-feature-pipeline==2.0.0
29
30# Copy application code
31COPY src/ ./src/
32COPY models/ ./models/
33
34# Set entrypoint
35ENTRYPOINT ["conda", "run", "--no-capture-output", "-n", "ml-pipeline-prod"]
36CMD ["python", "src/main.py"]
docker-compose.yml - Multi-container ML pipeline
 1version: '3.8'
 2
 3services:
 4  model-training:
 5    build:
 6      context: .
 7      secrets:
 8        - netrc
 9    environment:
10      - CUDA_VISIBLE_DEVICES=0
11      - MLFLOW_TRACKING_URI=http://mlflow:5000
12    volumes:
13      - ./data:/app/data
14      - ./outputs:/app/outputs
15    deploy:
16      resources:
17        reservations:
18          devices:
19            - driver: nvidia
20              count: 1
21              capabilities: [gpu]
22
23  jupyter:
24    build:
25      context: .
26      dockerfile: Dockerfile.jupyter
27    ports:
28      - "8888:8888"
29    volumes:
30      - ./notebooks:/app/notebooks
31    environment:
32      - JUPYTER_ENABLE_LAB=yes
33
34# Build secret, read from a netrc file on your machine that holds only
35# the CloudRepo entry (machine, login and password), kept outside the build context
36secrets:
37  netrc:
38    file: ${HOME}/cloudrepo.netrc

Without Compose, pass the same secret to docker build:

docker build --secret id=netrc,src=$HOME/cloudrepo.netrc -t ml-pipeline .

Jupyter Notebooks with Private Packages

Install private packages from a notebook with the same requirements-private.txt (see Mixing Conda-Forge and Private PyPI Packages), so neither the notebook nor its saved output holds a token. Start Jupyter as the user whose ~/.netrc holds the CloudRepo login:

Install packages within Jupyter notebook
 1# Cell 1: Install private packages from CloudRepo alone
 2import sys
 3!{sys.executable} -m pip install -r requirements-private.txt
 4
 5# Cell 2: Import and use
 6import acme_ml_core
 7from acme_ml_core import FeatureEngine, ModelRegistry
 8
 9# Initialize feature engine
10engine = FeatureEngine()
11features = engine.generate_features(df)
JupyterLab extensions for better experience
# Install useful extensions
conda activate ml-pipeline-prod

# Variable inspector
jupyter labextension install @lckr/jupyterlab_variableinspector

# Git integration
pip install jupyterlab-git

# Code formatting
pip install jupyterlab-code-formatter black isort

Multi-Environment Projects

Manage multiple environments for different stages:

environments/dev.yml - Development environment
 1name: project-dev
 2channels:
 3  - conda-forge
 4dependencies:
 5  - python=3.11  # Latest for development
 6  - numpy
 7  - pandas
 8  - jupyter
 9  - pytest
10  - black
11  - mypy
12  - pip:
13    # CloudRepo is this section's only index. pip reads the login
14    # for the host from ~/.netrc, so this file holds no token.
15    - --index-url https://[org-id].mycloudrepo.io/repositories/[repo-id]/simple
16    - -e ../acme-ml-core  # Editable local install
environments/prod.yml - Production environment
 1name: project-prod
 2channels:
 3  - conda-forge
 4dependencies:
 5  - python=3.10.11  # Pinned for production
 6  - numpy=1.24.3
 7  - pandas=2.0.2
 8  - pip:
 9    - --index-url https://[org-id].mycloudrepo.io/repositories/[repo-id]/simple
10    - acme-ml-core==3.2.1  # Pinned version
manage-environments.sh - Environment management script
 1#!/bin/bash
 2
 3# Environment management script
 4
 5create_env() {
 6    local env_name=$1
 7    local env_file=$2
 8
 9    echo "Creating environment: $env_name from $env_file"
10    mamba env create -f $env_file
11    echo "✅ Environment $env_name created"
12}
13
14update_env() {
15    local env_name=$1
16    local env_file=$2
17
18    echo "Updating environment: $env_name"
19    mamba env update -n $env_name -f $env_file --prune
20    echo "✅ Environment $env_name updated"
21}
22
23# Create all environments
24create_all() {
25    create_env project-dev environments/dev.yml
26    create_env project-test environments/test.yml
27    create_env project-prod environments/prod.yml
28}
29
30# Main script
31case "$1" in
32    create)
33        create_env $2 $3
34        ;;
35    update)
36        update_env $2 $3
37        ;;
38    create-all)
39        create_all
40        ;;
41    *)
42        echo "Usage: $0 {create|update|create-all} [env-name] [env-file]"
43        exit 1
44esac

CI/CD Integration

GitHub Actions with Conda

Integrate CloudRepo with GitHub Actions for automated testing and deployment:

.github/workflows/conda-ci.yml
 1name: Conda CI/CD Pipeline
 2
 3on:
 4  push:
 5    branches: [main, develop]
 6  pull_request:
 7    branches: [main]
 8
 9jobs:
10  test:
11    runs-on: ${{ matrix.os }}
12    strategy:
13      matrix:
14        os: [ubuntu-latest, windows-latest, macos-latest]
15        python-version: ['3.9', '3.10', '3.11']
16
17    steps:
18      - uses: actions/checkout@v3
19
20      - name: Setup Miniconda
21        uses: conda-incubator/setup-miniconda@v2
22        with:
23          python-version: ${{ matrix.python-version }}
24          miniforge-version: latest
25          activate-environment: test-env
26          environment-file: environment.yml  # conda and public pip packages
27          auto-activate-base: false
28
29      - name: Install private packages from CloudRepo alone
30        shell: bash -l {0}
31        env:
32          CLOUDREPO_USERNAME: ${{ secrets.CLOUDREPO_USER }}
33          CLOUDREPO_API_TOKEN: ${{ secrets.CLOUDREPO_API_TOKEN }}
34        run: |
35          (umask 077 && printf 'machine [org-id].mycloudrepo.io\nlogin %s\npassword %s\n' \
36            "$CLOUDREPO_USERNAME" "$CLOUDREPO_API_TOKEN" >> ~/.netrc)
37          pip install -r requirements-private.txt
38
39      - name: Install the project
40        shell: bash -l {0}
41        run: |
42          conda info
43          conda list
44          # Its dependencies are already installed by the two steps above
45          pip install --no-deps -e .
46
47      - name: Run tests
48        shell: bash -l {0}
49        run: |
50          pytest tests/ -v --cov=your_package --cov-report=xml
51
52      - name: Upload coverage
53        uses: codecov/codecov-action@v3
54        with:
55          file: ./coverage.xml
56
57  publish:
58    needs: test
59    runs-on: ubuntu-latest
60    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
61
62    steps:
63      - uses: actions/checkout@v3
64
65      - name: Setup Python
66        uses: actions/setup-python@v4
67        with:
68          python-version: '3.10'
69
70      - name: Build package
71        run: |
72          pip install build
73          python -m build
74
75      - name: Publish to CloudRepo
76        env:
77          TWINE_USERNAME: ${{ secrets.CLOUDREPO_USER }}
78          TWINE_PASSWORD: ${{ secrets.CLOUDREPO_API_TOKEN }}
79        run: |
80          pip install twine
81          twine upload --non-interactive \
82            --repository-url https://[org-id].mycloudrepo.io/repositories/[repo-id] \
83            dist/*

GitLab CI

Configure GitLab CI for Conda and CloudRepo:

.gitlab-ci.yml
 1# conda-forge's image: continuumio/miniconda3 is deprecated
 2image: condaforge/miniforge3:latest
 3
 4# Set CLOUDREPO_USERNAME and CLOUDREPO_API_TOKEN as masked CI/CD variables.
 5# The third command writes them to ~/.netrc, where pip reads the login for the
 6# host; nothing here sets a pip index.
 7before_script:
 8  - conda env create -f environment.yml          # conda and public pip packages
 9  - conda activate ml-pipeline
10  - |
11    (umask 077 && printf 'machine [org-id].mycloudrepo.io\nlogin %s\npassword %s\n' \
12      "$CLOUDREPO_USERNAME" "$CLOUDREPO_API_TOKEN" >> ~/.netrc)
13  - pip install -r requirements-private.txt      # private packages, CloudRepo alone
14
15stages:
16  - test
17  - build
18  - deploy
19
20test:unit:
21  stage: test
22  script:
23    - conda activate ml-pipeline
24    - pytest tests/unit -v --junitxml=report.xml
25  artifacts:
26    reports:
27      junit: report.xml
28
29test:integration:
30  stage: test
31  script:
32    - conda activate ml-pipeline
33    - pytest tests/integration -v
34
35build:package:
36  stage: build
37  script:
38    - conda activate ml-pipeline
39    - python -m build
40  artifacts:
41    paths:
42      - dist/
43    expire_in: 1 week
44
45deploy:cloudrepo:
46  stage: deploy
47  only:
48    - main
49    - tags
50  variables:
51    TWINE_USERNAME: $CLOUDREPO_USER
52    TWINE_PASSWORD: $CLOUDREPO_API_TOKEN
53  script:
54    - pip install twine
55    - twine upload --non-interactive \
56        --repository-url https://[org-id].mycloudrepo.io/repositories/[repo-id] \
57        dist/*

Azure ML Pipelines

Integrate with Azure Machine Learning pipelines:

azure-pipelines.yml
 1trigger:
 2  branches:
 3    include:
 4      - main
 5      - develop
 6
 7pool:
 8  vmImage: 'ubuntu-latest'
 9
10variables:
11  - group: cloudrepo-credentials
12
13stages:
14- stage: Build
15  jobs:
16  - job: CondaBuild
17    strategy:
18      matrix:
19        Python39:
20          python.version: '3.9'
21        Python310:
22          python.version: '3.10'
23        Python311:
24          python.version: '3.11'
25
26    steps:
27    - task: UsePythonVersion@0
28      inputs:
29        versionSpec: '$(python.version)'
30
31    - bash: |
32        wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh
33        bash miniconda.sh -b -p $HOME/miniconda
34        export PATH="$HOME/miniconda/bin:$PATH"
35        conda env create -f environment.yml
36      displayName: 'Setup Conda Environment'
37
38    - bash: |
39        source $HOME/miniconda/bin/activate ml-pipeline
40        (umask 077 && printf 'machine [org-id].mycloudrepo.io\nlogin %s\npassword %s\n' \
41          "$CLOUDREPO_USER" "$CLOUDREPO_API_TOKEN" >> ~/.netrc)
42        pip config set global.index-url https://[org-id].mycloudrepo.io/repositories/[repo-id]/simple
43        pip install -e .[dev]
44      displayName: 'Install Dependencies'
45      env:
46        CLOUDREPO_USER: $(CLOUDREPO_USER)
47        CLOUDREPO_API_TOKEN: $(CLOUDREPO_API_TOKEN)
48
49    - bash: |
50        source $HOME/miniconda/bin/activate ml-pipeline
51        pytest tests/ --junitxml=junit/test-results.xml --cov --cov-report=xml
52      displayName: 'Run Tests'
53
54    - task: PublishTestResults@2
55      inputs:
56        testResultsFiles: '**/test-results.xml'
57
58    - task: PublishCodeCoverageResults@1
59      inputs:
60        codeCoverageTool: 'Cobertura'
61        summaryFileLocation: '$(System.DefaultWorkingDirectory)/coverage.xml'
62
63- stage: Deploy
64  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
65  jobs:
66  - job: PublishPackage
67    steps:
68    - bash: |
69        pip install build twine
70        python -m build
71        twine upload --non-interactive \
72          --repository-url https://[org-id].mycloudrepo.io/repositories/[repo-id] \
73          dist/*
74      displayName: 'Publish to CloudRepo'
75      env:
76        TWINE_USERNAME: $(CLOUDREPO_USER)
77        TWINE_PASSWORD: $(CLOUDREPO_API_TOKEN)

Troubleshooting Common Issues

Authentication Issues

Problem: 401 Unauthorized errors when installing packages

Solution: Verify credentials and URL format
# Check current pip configuration, with the credentials in each URL masked
pip config list | sed -E 's#://[^/]*@#://***@#g'

# Verify URL format (note the /simple suffix for PyPI); the login is in ~/.netrc
# Correct: https://[org-id].mycloudrepo.io/repositories/[repo-id]/simple
# Wrong:   https://[org-id].mycloudrepo.io/repositories/[repo-id]

# Test authentication
curl -u you@example.com https://[org-id].mycloudrepo.io/repositories/[repo-id]/simple

Problem: Credentials visible in conda environment export

Solution: Use environment variables or keyring
# Use environment variables
export CLOUDREPO_INDEX=https://[org-id].mycloudrepo.io/repositories/[repo-id]/simple

# In environment.yml, reference without credentials
dependencies:
  - pip:
    - --index-url ${CLOUDREPO_INDEX}

Package Resolution Conflicts

Problem: Conda and pip package versions conflict

Solution: Install conda packages first, then pip
# Best practice order
conda install numpy pandas scikit-learn
pip install your-private-package

# Never do this (pip first, then conda)
pip install numpy
conda install numpy  # May downgrade or conflict

Problem: Dependency resolver timeout with complex requirements

Solution: Use mamba or simplify requirements
# Install mamba for faster resolution
conda install -c conda-forge mamba

# Use mamba instead
mamba env create -f environment.yml

# Or simplify by pinning major versions only
dependencies:
  - numpy=1.24.*  # Instead of exact version
  - pandas=2.*

SSL/TLS Certificate Issues

Problem: SSL verification errors with corporate proxies

Solution: Configure certificates properly
# Export corporate certificate
export REQUESTS_CA_BUNDLE=/path/to/corporate-ca-bundle.crt
export SSL_CERT_FILE=/path/to/corporate-ca-bundle.crt

# Or configure in pip
pip config set global.cert /path/to/corporate-ca-bundle.crt

# For conda
conda config --set ssl_verify /path/to/corporate-ca-bundle.crt

Environment Reproducibility

Problem: Different team members get different package versions

Solution: Use lock files and exact versions
# Generate exact environment snapshot
conda list --explicit > conda-explicit.txt
pip freeze > requirements-lock.txt

# Recreate exact environment
conda create --name myenv --file conda-explicit.txt
conda activate myenv
pip install -r requirements-lock.txt

Problem: Builds fail in CI but work locally

Solution: Match CI environment exactly
# Export local environment
conda env export --no-builds > ci-environment.yml

# In CI, use exact same environment
conda env create -f ci-environment.yml

Performance Issues

Problem: Slow package downloads from CloudRepo

Solution: Use pip caching and parallel downloads
# Enable pip cache
pip config set global.cache-dir /path/to/cache

# Use parallel downloads (pip 20.3+)
pip install --use-feature=fast-deps your-package

# For conda, use mamba
mamba install your-packages

Problem: Large conda environments taking too much space

Solution: Clean conda cache and use hard links
# Clean package cache
conda clean --all

# Use hard links to save space
conda config --set allow_softlinks false

# Pack environment for distribution
conda pack -n myenv -o myenv.tar.gz

Common Error Messages

Error reference and solutions
ERROR: Could not find a version that satisfies the requirement
→ Check package name spelling and version availability
→ Verify repository URL includes /simple for PyPI

ERROR: No matching distribution found
→ Package might not exist in CloudRepo
→ Check if package supports your Python version/platform

CondaHTTPError: HTTP 401 UNAUTHORIZED
→ Invalid credentials or expired token
→ Create new repository user in CloudRepo admin

ResolvePackageNotFound
→ Package not available in specified channels
→ Add appropriate channel or install via pip

InvalidVersionSpec
→ Version specification syntax error
→ Use correct syntax: ==, >=, ~=, etc.

Summary

CloudRepo provides robust support for Conda and Miniconda users through its PyPI repository functionality, enabling data science teams to:

  • Securely host and share proprietary Python packages within Conda environments

  • Combine the best of both worlds by using conda-forge for optimized binaries and CloudRepo for private packages

  • Maintain reproducible environments across development, testing, and production

  • Integrate seamlessly with existing CI/CD pipelines and MLOps workflows

  • Save significantly on infrastructure costs compared to enterprise alternatives

For additional support or questions about using CloudRepo with Conda, please contact our support team at support@cloudrepo.io.

See also