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:
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:
Conda or Miniconda Installation
Conda (via Anaconda) or Miniconda installed on your system
Verify installation:
conda --version
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).
# 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
--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:
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
--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
# 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
# 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
machine [org-id].mycloudrepo.io
login you@example.com
password YOUR_REPOSITORY_TOKEN
chmod 600 ~/.netrc
Environment Variables for CI/CD
# 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:
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)
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:
# 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:
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
# 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:
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:
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:
--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:
# 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
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:
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:
# 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
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
# 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:
# 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
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.
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"]
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:
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)
# 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:
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
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
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:
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:
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:
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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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: 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
Python Repositories - Core Python repository documentation
Poetry Repositories - Using Poetry with CloudRepo
Use CloudRepo’s PyPI index from Pixi - Pixi package management
UV Repositories - Ultra-fast UV package installer
Continuous Integration and Deployment - CI/CD setup guides