Set up a project directory

Last updated on 2025-10-26 | Edit this page

Overview

Questions

  • How should we structure our project ?
  • What is __init__.py ?
  • How should be name our packages ?

Objectives

  • To understand how to structure a project effectively in order to package it successfully.
  • To recognise the importance of the __init__.py file and know where to place it.
  • To assign unique yet meaningful names to packages.

Introduction


It is essential to structure your project correctly, include the necessary files, and provide packages with names that are both unique and understandable.

Packages are used to organise modules within a Python project. As projects often consist of several modules, grouping them into packages helps to keep the codebase structured, maintainable, and easy to navigate.

Each package must contain a special file named __init__.py. The presence of this file indicates to Python that the folder is a package, thereby allowing it to be imported into your code.

It is a recommended practice to place your Python packages inside a src/ directory. This structure helps prevent accidental imports from the working directory and ensures your tests accurately reflect how your package will be used after installation.

Project Structure


A typical project would look like :

greet_me/
└── src/my_package/
    ├── __init__.py
    ├── happy.py
    └── sad.py

Let us create a similar structure within our codespace.

BASH

pixi init --format pyproject

OUTPUT

✔ Created /workspaces/pixi_demo/pyproject.toml

This generates the following structure:

image

pyproject.toml : The initial pyproject.toml file generated may look like this:

TOML

[project]
authors = [{name = "Priyanka Demo", email = "demo@users.noreply.github.com"}]
dependencies = []
name = "greet_me"
requires-python = ">= 3.11"
version = "0.1.0"

[build-system]
build-backend = "hatchling.build"
requires = ["hatchling"]

[tool.pixi.workspace]
channels = ["conda-forge"] #Download and install Conda packages from the conda-forge channel
platforms = ["linux-64"]

[tool.pixi.pypi-dependencies] #Add dependencies here which needs to be installed from PyPI
greet_me = { path = ".", editable = true }

[tool.pixi.tasks]

To add libraries via Pixi use the pixi add command. Add the requests library:

BASH

pixi add requests

OUTPUT

✔ Added requests >=2.32.5,<3

This will create/update the [tool.pixi.dependencies] section in pyproject.toml.

TOML

[tool.pixi.dependencies]
requests = ">=2.32.5,<3"

It also generates a pixi.lock file which may look somewhat like the image below.

image

To remove a package, use this command and check that pyproject.toml is corrected and the package is removed from there.

BASH

pixi remove requests

OUTPUT

✔ Removed requests

To add libraries from PyPI via Pixi:

BASH

pixi add --pypi requests

OUTPUT

✔ Added requests >=2.32.5, <3
Added these as pypi-dependencies.

Check the pyproject.toml file. These get added under the [project] section

TOML

[project]
authors = [{name = "Priyanka Demo", email = "demo@users.noreply.github.com"}]
dependencies = ["requests>=2.32.5,<3"]
name = "greet_me"

Other commands, that can be later explored :

pixi lock : Generates or updates the pixi.lock file by resolving exact package versions for reproducible environments. This is conceptually similar to pip freeze, but instead of listing installed packages, it proactively locks dependency versions.

BASH

pixi lock

OUTPUT

✔ Lock-file was already up-to-date

pixi install : Creates or updates the project environment based on your configuration files (pixi.toml / pyproject.toml and pixi.lock). Useful to run after cloning a repository.

BASH

pixi install

OUTPUT

✔ The default environment has been installed.

pixi update : It refreshes and upgrades dependencies in your Pixi project to their latest compatible versions, updating both the environment and the lock file.

BASH

pixi update

OUTPUT

▪ solving              [━━━━━━━━━━━━━━━━━━━━]  0/1
▪ updating lock-files    [━━━━━━━━━━━━━━━━━━━━] 0/2

OUTPUT

✔ Lock-file was already up-to-date

pixi tree : It shows a dependency tree for your current Pixi project or environment

BASH

pixi tree

OUTPUT

├── requests 2.32.5
│   ├── charset_normalizer 3.4.4
│   ├── idna 3.11
│   ├── urllib3 2.5.0
│   └── certifi 2025.10.5
├── python 3.14.0
│   ├── bzip2 1.0.8
│   │   └── libgcc 15.2.0
...

Adding Modules


Lets create these 2 files: happy.py, sad.py in the folder src/greet_me.

Please note, in VSCode inside GitHub codepsaces, you mabe be prompted for below, when creating a python file. So just Install it. image

PYTHON

# happy.py <- A module
def greet_happy():
    return "Yay! happy day! 😀"

PYTHON

# sad.py <- A module
def greet_sad():
    return "Oh no… I’m feeling a bit down today. 😢"

The overall project structure should then resemble:

greet_me/
├── .pixi
├── .gitattributes
├── .gitignore
├── LICENSE
├── pyproject.toml
├── pixi.lock         # auto-generated, do not edit
└── src/greet_me/
    ├── __init__.py
    ├── happy.py
    └── sad.py
image

Running a Task


task is a command alias that you can execute easily via the CLI (e.g., pixi run task-name).

Run the following command to add a task and observe the changes in pyproject.toml file:

BASH

pixi task add start "python -c 'from greet_me import happy; print(happy.greet_happy())'"

pyproject.toml file:

TOML


[tool.pixi.tasks]
start = "python -c 'from greet_me import happy; print(happy.greet_happy())'"

Then execute:

BASH

pixi run start

OUTPUT

Yay! happy day! 😀

You can read more about tasks here, which contains all the advanced use cases needed in a professional setting.

Key Points
  • Follow the appropriate folder structure.
  • Always include the __init__.py file in packages.
  • Sequence of Pixi commands: initaddrunremovelockinstallupdate.
  • Define / check [project], [dependencies] and [tasks] in your pyproject.toml file.
  • Keep your project dependencies lean and remove unused packages.