Python Environments & Conda
Why ecologists who never thought they'd touch a package manager need one anyway, and how to set it up so you don't fight your laptop for the rest of the course.
1. The problem environments solve
Here is a real situation you will hit in this course (and in every Python project for the rest of your career):
- Lab 6 uses
birdnet, which pulls intensorflow 2.21. - Lab 7 uses PNW-Cnet via
pycnet-audio, which needs Python 3.8–3.11 and a specifictensorflowversion. - Lab 2 / 5 use PyTorch, which works fine on Python 3.13 but pulls in its own NumPy preferences.
- Your operating system may also have its own Python (macOS ships 3.13; Ubuntu 3.12) that you should not pollute with anything project-specific.
If you pip install all of these into one Python, sooner or later one will
overwrite a shared dependency at a version that breaks another. You'll get a four-line
cryptic error, lose two hours debugging, and learn the wrong lesson ("Python is bad").
The right lesson is: each project gets its own isolated Python — an
"environment" — and they don't share packages.
An environment is just a folder containing its own Python interpreter
and its own copy of every package it needs. When you activate the environment,
typing python or pip in your shell uses that folder's
Python instead of the system one.
2. The cast of characters
| Name | What it is | When to reach for it |
|---|---|---|
venv |
Built into Python. Creates a lightweight environment that uses your existing
Python and installs packages with pip. |
Quick projects where you already have the right Python version and only need
pure-Python packages. Used by the instructor for the answer-key venv
(.venv/ in the course folder). |
conda |
Heavier. Installs an entire Python interpreter and packages, including
non-Python tools like sox, ffmpeg, gdal. |
Anything ML-flavoured (TensorFlow, PyTorch with CUDA), anything that needs a specific Python version, anything that depends on a binary tool. This is the default in this course. |
| Miniforge | A small conda installer that defaults to the open conda-forge
package channel (free of Anaconda's commercial licensing concerns). |
What we recommend installing. It gives you conda and
mamba. |
mamba |
A drop-in replacement for the slow parts of conda (especially
dependency solving). Same commands, ~10x faster. |
Once you have conda working, you may want to substitute
mamba for conda in commands like create
and install. Ships with Miniforge. |
pip |
The Python-only package installer. Available in any conda or venv env. | Inside a conda env, use it for packages that aren't on conda-forge (most ML packages by the time you read this). |
3. Install Miniforge (one time per laptop)
macOS
# Recommended: via Homebrew
brew install --cask miniforge
# Initialize your shell (zsh is default on modern macOS)
conda init zsh
# Close and reopen your terminal so the changes take effect.
# Verify:
conda --version
mamba --version
Windows
Two equally fine options:
# Option A: WinGet
winget install CondaForge.Miniforge3
# Option B: Download from https://github.com/conda-forge/miniforge and run the .exe
# Accept all defaults.
# Verify in a NEW PowerShell:
conda --version
mamba --version
Windows users: search the Start menu for "Miniforge Prompt" the first
time. It's a pre-configured terminal where conda already works. After
conda init powershell, regular PowerShell will work too.
Linux / WSL
curl -L -O "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh"
bash Miniforge3-*.sh -b -p ~/miniforge3
~/miniforge3/bin/conda init bash # or zsh, fish, etc.
# Restart shell, verify:
conda --version
4. Your first environment (do this once now)
Let's make the course environment you'll use for all the Python labs:
# Create a fresh env called "aiecol" with Python 3.11 (the sweet spot — works with
# pycnet-audio AND PyTorch AND birdnet at the same time).
mamba create -n aiecol -c conda-forge python=3.11 sox ffmpeg -y
# Switch into it
conda activate aiecol
# Your prompt now shows (aiecol).
# Install the Python packages. We use pip here because most ML packages publish to
# PyPI faster than to conda-forge. This is a totally normal and supported pattern
# inside a conda env.
pip install numpy pandas matplotlib scikit-learn pillow requests exifread \
soundfile librosa pyyaml tqdm \
torch torchvision \
ultralytics birdnet
# Sanity check
python -c "import torch, ultralytics, librosa, birdnet; print('all good')"
That's it. You now have one isolated environment with everything Lab 2–7 needs. Whenever you start a new terminal session and want to work on the course, run:
conda activate aiecol
and your prompt will say (aiecol) instead of (base). To leave
it (and return to the base/system Python):
conda deactivate
(base)? Every Miniforge install ships with a
"base" environment that is auto-activated when you open a terminal. Never install
project packages into base. Always create a named env per project.
The base env is for conda itself.
5. The second environment — an example of why this matters
For Lab 7 we use PNW-Cnet via pycnet-audio, which is fussier — it
requires Python 3.8–3.11 and a specific TensorFlow version that fights
with birdnet's newer TensorFlow. Easiest fix: a separate environment for
that one tool.
mamba create -n pycnet -c conda-forge sox python=3.11 -y
conda activate pycnet
pip install pycnet-audio
# Use it
pycnet process /path/to/audio -c v5 -a
# When done, go back to your main course env
conda deactivate
conda activate aiecol
You now have two envs: aiecol (everything else) and pycnet
(just PNW-Cnet). Switching between them is free.
6. environment.yml — saving and sharing an env
When your project gets serious (a manuscript, a thesis, your final project for this
course), write down exactly what's in your env so you and your collaborators
can recreate it later. The standard way is an environment.yml file:
# Dump the current env to a portable file
conda env export --from-history > environment.yml
# Or, more commonly, write it by hand to be deliberate:
cat > environment.yml <<'EOF'
name: my_project
channels:
- conda-forge
dependencies:
- python=3.11
- sox
- ffmpeg
- pip
- pip:
- numpy
- pandas
- librosa
- birdnet
EOF
# Recreate it later (yours or a colleague's machine)
mamba env create -f environment.yml
conda activate my_project
--from-history? A raw conda env export
lists every transitive dependency at exact versions, which often doesn't reproduce
cross-platform (a macOS export won't install on Linux because some packages have
different platform-specific builds). --from-history exports only the
packages you explicitly asked for — much more portable.
Commit environment.yml to git. Don't commit the env folder itself; add
.conda/ and envs/ to your .gitignore.
7. pip vs conda — when to use which
Inside a conda env, both pip install X and conda install X
work. Which should you pick?
- Use
conda(ormamba) for: Python itself, anything with native compiled code that's tricky to build (gdal,geos,cartopy,r-base), non-Python tools (sox,ffmpeg,git). If a package is available on conda-forge, prefer that. - Use
pipfor: ML frameworks that ship newest on PyPI (torch,ultralytics,birdnet,pycnet-audio) and small pure-Python packages. - Don't mix them for the same package. If you install
numpywith conda and laterpip install -U numpy, conda's bookkeeping gets out of sync and weird things happen. Pick one source per package. - Always install conda packages first, then pip packages, when building a new env. That way pip sees the conda-installed dependencies and doesn't try to replace them.
8. Activating envs in different tools
RStudio terminal pane
RStudio's Terminal tab opens a normal shell. Just type
conda activate aiecol and you're in. You may need to first
conda init zsh (macOS) or conda init bash (Linux) once for
that shell to know about conda.
Claude Code
Same trick — Claude Code runs commands in a normal shell. Before starting
Claude, activate your env in that terminal. Or, to make it automatic per project, add
to your project's CLAUDE.md:
# in CLAUDE.md
Always run Python via the `aiecol` conda env. Never `pip install` into base.
If a command needs the env, prefix with `conda run -n aiecol`.
You can also use conda run -n aiecol python ... for one-off commands
without changing the active env.
VS Code
Cmd/Ctrl-Shift-P → "Python: Select Interpreter" → pick the one whose path
ends in envs/aiecol/bin/python. After that, VS Code's "Run Python File"
button and the integrated terminal automatically use that env.
Jupyter
conda activate aiecol
pip install jupyterlab
python -m ipykernel install --user --name aiecol --display-name "Python (aiecol)"
# Then in JupyterLab, pick the "Python (aiecol)" kernel.
9. When you don't need an environment
Be honest with yourself; not every script needs a fresh env. If you're:
- Writing a 10-line script that only uses the Python standard library, OR
- Inspecting a CSV with a one-liner in the REPL,
just use the base env or system Python. Spinning up a fresh env for every trivial task gets in the way of fast iteration.
But: the moment you pip install anything for a one-liner script, it
has become a project. Make it an env.
10. When to use one env per project vs one big env
Two reasonable workflows:
- One env per project — the strict-isolation approach. Best for: anything you'll publish, anything you'll share, anything where the exact dependency set matters. Slight tax: more disk space, more switching.
- One big "everything" env — what we use in this course
for Labs 1–6 and 8–10 (the
aiecolenv). Best for: coursework and exploration where you're constantly bouncing between tools. Tax: when one tool needs an incompatible version, you have to make a side env (as we do forpycnet).
The right default for a research project is one env per repo, with the
environment.yml living in the repo root next to README.md.
11. Pitfalls and rescue commands
| Symptom | Cause | Fix |
|---|---|---|
conda activate aiecol → "command not found: conda" |
You skipped conda init, or the shell hasn't been restarted. |
Run conda init zsh (or your shell), close the terminal, open
a new one. |
| conda solver hangs for many minutes | Real conda solver is slow. Many old StackOverflow answers say so. | Use mamba instead: mamba install .... Ships with
Miniforge. |
ModuleNotFoundError: No module named 'X' after installing |
You're not in the env you think you are. | Check the env name in your prompt; which python should point at
the env's bin folder. Run conda activate <env>. |
| Two envs got mixed up; one is acting weird | You pip-installed into base, or pip-overwrote a conda-installed package. | Delete and recreate: conda env remove -n broken, then create
from your environment.yml. |
| Disk fills up with env folders | Each env is ~1–5 GB, mostly PyTorch wheels. | conda clean --all reclaims a few GB; conda env list
shows what's around; remove old ones with conda env remove -n
old_env. |
| "InvalidVersionSpec" or "ResolvePackageNotFound" | Two packages require incompatible versions. | Pin Python (python=3.11) and the major conflicting package
explicitly; try installing one at a time to see which causes the conflict. |
| Apple Silicon: "wheel not available for platform" | Some packages don't have arm64 wheels yet. | Try conda-forge (broader arm64 coverage); or, as a last resort, set
CONDA_SUBDIR=osx-64 to install x86_64 versions that run under
Rosetta. |
12. Cheat sheet
# list all envs
conda env list
# create new env from scratch
mamba create -n NAME -c conda-forge python=3.11 PACKAGE1 PACKAGE2 -y
# create from a yml file
mamba env create -f environment.yml
# activate / deactivate
conda activate NAME
conda deactivate
# install / uninstall
mamba install -c conda-forge PACKAGE # preferred
pip install PACKAGE # for ML / PyPI-only packages
# save / share
conda env export --from-history > environment.yml
git add environment.yml && git commit -m "freeze env"
# remove
conda env remove -n NAME
# what version of X is installed?
conda list PACKAGE
pip show PACKAGE
One last sanity rule: if you can't remember whether you're in the right
env, run which python (Unix) or where python (Windows).
The path tells you exactly which Python you're about to use. Trust the path, not your
memory.