Your Python Project
On this page
Every piece of Python you write this semester lives in one folder with a record of what it needs to run. That folder is your project, and it sits inside your course repository, so it travels with your work to GitHub and back.
This page walks through starting your project, and it is the reference for the commands that manage it afterward.
Why a project at all#
This course grades whether your numbers are right, and the way anybody checks a number is to run the thing that produced it. A project makes that possible. It writes down which version of Python you used and which version of every package you installed, in two small files that you commit alongside your notebooks. Somebody who clones your repository types one command and has the setup you had.
Starting a project#
You do this once, in your course repository. If you do not have one yet, start with Getting Started.
Open your repository and a terminal#
- Open GitHub Desktop and check that Current repository, at the top left, shows your course repository:
oim7510oroim6301. - Click Open in Visual Studio Code. VS Code opens with your repository's folder, and the file list on the left shows
README.md. - Choose View → Terminal. A panel opens at the bottom, and the prompt in it ends in your repository's name.
Opening VS Code from GitHub Desktop every time keeps the terminal in the right folder. The Terminal explains why, and Where Am I Typing? shows what each prompt looks like.
Your repository must not be in OneDrive, iCloud Drive, Dropbox or Google Drive. Those programs sync files while your code runs and can break a repository. If yours is in one of them, move it first: the steps are in the FAQ, under Your repository.
Check that the tools are there. Paste each line into the terminal and press Enter:
git --version
uv --versionEach prints a version number. If one prints command not found or is not recognized, see The Terminal.
Make it a project#
uv init --app --no-package --python 3.14The first run can take a minute or two. If Python 3.14 is not on your machine yet, uv downloads it, about 30 MB. You never install Python yourself and you never pick it from a menu.
Each part of the command does a job:
--appmarks the project as your own analysis, which nobody installs as a package.--no-packageturns off the packaging machinery that goes with a package. Without it, recent versions of uv build and install your own project every time you add anything, which prints a wall of output and gives you one more thing that can break.--python 3.14pins the version in a file called.python-version, so uv uses the same Python here, on your next computer, and on mine when you show me a problem. Leave it out and uv takes whatever Python your machine offers first, which on macOS can be one that shipped years ago.
The command adds pyproject.toml, .python-version and main.py to your repository and touches nothing else. The project files says what the first two are for, and you may keep or delete main.py.
Check that it worked:
uv run python -c "print('it works')"It prints it works, which tells you that uv runs, Python is installed, and your project can execute code. Any week you suspect your setup has broken, run it again before you debug anything else.
Keep the right files out of git#
Use the course .gitignore. Step 11 of Getting Started replaces GitHub's template with it. It lists __pycache__/, which Python writes beside your code, and __marimo__/, where marimo keeps every cell's output, and committing either fills your history with noise. The .venv folder holding your packages ignores itself, which uv arranges when it builds the folder.
Open your first notebook#
uv add marimo
uv run marimo editYour browser opens a page listing the notebooks in your project. There are none yet, so click Create a new notebook and give it a plain name.
To stop marimo, click the terminal and press Ctrl+C, which is Ctrl on macOS too. marimo asks Are you sure you want to quit? (y/N), so type y and press Enter.
Then set up your agent#
Your agent runs on the key that Babson's AI team emails you. Your AI Tools and Babson Key has the steps for marimo and for VS Code.
The project files#
uv init creates the first two, and uv writes the third the first time you run uv add, uv run or uv sync. After that, uv add and uv remove keep the first and the third in step, and uv python pin is the only thing that touches the second.
pyproject.toml is the one you read. It holds the version of Python your project needs and the list of packages you asked for, and it is short:
[project]
name = "<course-code>"
version = "0.1.0"
requires-python = ">=3.14"
dependencies = [
"marimo[recommended]>=0.24.2",
"duckdb>=1.5.5",
].python-version is one line long, and on a new project it holds 3.14. It decides which Python actually runs. The requires-python line in pyproject.toml is a floor, meaning 3.14 or newer, while this file names the exact one. Change it with uv python pin 3.14. Editing it by hand to a version below the floor gives you an error that names the fix, so this is a mistake that announces itself.
uv.lock is the one you leave alone. It records the exact version of every package that got installed, including the ones your packages pulled in behind your back, each with a checksum. It is long and it is generated.
Commit all three. They belong to the work in the same way the notebook does.
Never edit uv.lock by hand. One wrong character and both uv sync and uv run stop with Failed to parse uv.lock, which leaves you unable to run anything until it is fixed. If it happens, delete the file and run uv sync, which builds a fresh one.
Editing pyproject.toml by hand is allowed, and uv catches up the next time you run something. Use uv add and uv remove anyway. They keep both files in step, and they are faster than typing a version number correctly.
Commands you will use#
| command | when |
|---|---|
uv init --app --no-package --python 3.14 |
once, in a new repository |
uv add requests |
whenever your work needs a package it does not have |
uv run marimo edit |
every time you sit down to work |
uv sync |
when you open somebody else's project, or your own on a second computer |
uv run is the one you type most. It puts your project's packages in front of whatever comes after it, so there is no environment to activate and nothing to remember between opening the terminal and running your code.
Open the project. uv run marimo edit with no file name after it gives you a page listing every notebook in your project, subfolders included, and you click the one you want. You can pass a file name to jump straight to one, and there is rarely a reason to. Typing a file name is how you meet a FileNotFoundError for a file that exists, spelled slightly differently.
The keys and menus inside a notebook are in marimo Basics.
Where files go#
Put a file into your repository before you open it. Your browser saves a download to its default folder, usually Downloads, or to wherever you saved the last one. Move it into the folder it belongs in, then check that VS Code's file list shows it there. marimo lists only the notebooks inside the folder you started it from, so a notebook left in Downloads does not appear.
| The file | Where it goes |
|---|---|
| A session notebook | notebooks/ |
| A data file a notebook reads | data/ |
| A handbook you only read | handbooks/, if you keep it at all |
A script you run on its own, like hello.py |
scripts/, run from the root folder as uv run python scripts/hello.py |
| A project | its own folder under projects/, such as projects/mp1/ |
| The export of a notebook you publish | docs/, as in Publishing a Notebook |
Build a data path from the notebook's own folder. A relative path is read from the folder you started marimo in. mo.notebook_dir() returns the folder the notebook is in, and the data handbook shows how to get from there to the data folder.
If you would rather use Jupyter#
You do not have to. marimo is what this course uses and what the handed-out notebooks are written in. But Jupyter is not forbidden, and it lives in the same project:
uv add jupyterlab
uv run jupyter labSame project, same packages, no second environment to keep in step.
Know this before you try it. A marimo notebook is a .py file, and JupyterLab opens a .py file as plain text with no cells. What you want instead is the Jupyter version offered beside each notebook on its session page, which is an .ipynb. It reads and it runs, with two exceptions, because both are marimo features: the interactive controls do nothing, and a SQL cell stops with an error.
Adding a package#
uv add requests
uv add yfinance
uv remove yfinanceYou can also let marimo do it. A cell that imports something your project does not have stops with ModuleNotFoundError, and marimo offers to install it. Accept the offer. It runs uv add for you, and your pyproject.toml gains a line exactly as if you had typed the command. Open the file afterward and look, at least the first time.
This works because you opened the notebook from inside your project. A notebook opened somewhere else installs into a temporary environment that records nothing, and the install disappears the next time anybody runs uv sync. Keep your notebooks in your repository and this never comes up.
Opening your work somewhere else#
On a new laptop, or on a classmate's machine during pair work:
uv syncIt reads uv.lock and installs precisely what that file says, down to the version. Nothing resolves, nothing upgrades, and you get the environment your commits describe.
uv sync also removes anything in your environment that the lock file does not list. That is deliberate. It is what keeps your environment matching your repository instead of drifting away from it over a semester.
The Python version#
Because .python-version is committed, your project runs on the same Python on your machine, on mine, and on a classmate's.
Leave it at 3.14 for the semester, even after a newer Python is released. Packages containing compiled code publish ready-built versions for a new Python on their own schedule, and until they do, installing one means compiling it on your own machine. Upgrading in the middle of the term can therefore produce an error that nobody else in the class is able to reproduce.
What to avoid#
uv pip install. It installs a package without writing it down anywhere. Your work runs, you commit, and the person who clones your repository gets a ModuleNotFoundError. Your own next uv sync deletes it too. Use uv add.
uv venv. Older instructions tell you to create an environment before installing anything. uv add, uv run and uv sync each create it for you the first time they need it.
Anaconda and conda. Most Python tutorials on the internet start there. The Python environments guide explains what those tools are and how to read a tutorial written for one.
Hand-edited uv.lock. Covered above, and worth repeating because an agent will occasionally suggest it.
When something goes wrong#
error: No pyproject.toml found in current directory or any parent directory. You are standing outside your project. Look at the terminal prompt, check the folder name at the end of it, and open the right folder through GitHub Desktop.
ModuleNotFoundError: No module named 'pandas'. Your project does not have that package. Run uv add pandas, or accept marimo's offer to install it.
error: Failed to parse uv.lock. Delete uv.lock and run uv sync.
error: The Python request from .python-version ... is incompatible with the project's Python requirement. Somebody edited one of the two version settings and left the other behind. Run uv python pin 3.14.
marimo says To enable code formatting, please install ruff. The formatter is missing, which happens in a project whose marimo was installed without recommended. Run uv add "marimo[recommended]" and reopen the notebook. Nothing else is affected while it is missing. That install is the first step of the marimo part of Your AI Tools and Babson Key, and the setting that uses it is Formatting on save in marimo Basics.
error: Failed to spawn: marimo. This prints for two different reasons, so try them in this order. Run uv add marimo. If that answers No pyproject.toml found, your Terminal is not inside your project: open VS Code from GitHub Desktop, open a new Terminal there, and run it again.
No internet, and you need to work. uv sync reads from a cache of everything uv has downloaded before, so it rebuilds your environment with no connection at all. Add --offline to stop it from trying to reach the network. Adding a package you have never installed still needs a connection.
Your disk is filling up. That cache is the reason. It grows all semester, and uv cache dir tells you where it is. uv cache prune deletes the parts nothing is using, which is the one to run first. uv cache clean empties it completely, which costs you the offline behavior above until each package is downloaded again.
Last updated: Sunday, 11/1/2026