> ## Documentation Index
> Fetch the complete documentation index at: https://fastapi2day.codewithsiva.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# How Python Finds Files and Modules: Paths Explained

> Understand Python's current working directory, sys.path, absolute vs relative imports, and how to fix the most common path errors.

Path errors are probably the most frustrating thing beginners encounter in Python. You write code that works perfectly in one situation and then a `FileNotFoundError` or `ModuleNotFoundError` appears the moment you move a file or run your script from a different folder. The good news is that once you understand two simple questions — *where am I?* and *where do I want to go?* — almost every path problem becomes straightforward to diagnose and fix. Don't worry if parts of this page don't click immediately; bookmark it and come back whenever you run into a path issue.

## The mental model

When working with multiple files, always ask yourself two things:

1. **Where am I?** — What folder is my Python script running from?
2. **Where do I want to go?** — What file or module do I need?

Then navigate accordingly:

* **Into subfolders** — use `/` for files, `.` for module imports
* **Up to the parent** — use `../` for files, add to `sys.path` for imports
* **Same folder** — just use the name directly

```python theme={null}
# From script.py, accessing different locations:
"data/sales.csv"        # Down into the data subfolder
"../config.json"        # Up one level to the parent folder
"helper.py"             # Same folder as script.py

# For imports:
import helper           # Same folder — no path needed
import data.processor   # Down into the data folder (data/processor.py)

# Importing from the parent folder requires sys.path:
import sys
sys.path.append("..")
import parent_module
```

## The current working directory

Python uses a "current working directory" as the starting point for all relative paths. Find out where that is:

```python theme={null}
import os

print(os.getcwd())  # Shows the folder Python is running from
```

Run this whenever you're confused about why a path isn't working — it tells you exactly where Python is looking.

## Finding files in your project

Given this structure:

```text theme={null}
my-project/
├── script.py
├── data.txt
└── folder/
    └── other.txt
```

When you run `script.py`:

```python theme={null}
# These paths work:
open("data.txt")           # Same folder as script.py
open("folder/other.txt")   # Down into the subfolder

# These paths don't work:
open("other.txt")          # Wrong — it lives in a subfolder
open("../parent.txt")      # Wrong — there's nothing above project root here
```

## Files vs modules — an important difference

Python treats regular data files and Python source files differently when you try to access them:

**Regular files (CSV, TXT, JSON)** — use `open()` with an exact path:

```python theme={null}
with open("data/sales.csv", "r") as file:
    content = file.read()
```

**Python modules (importing code)** — use `import` statements with dots, not slashes:

```python theme={null}
import mymodule                    # Looks for mymodule.py in sys.path
from folder.utils import helper    # Looks for folder/utils.py
```

## How Python finds modules

When you write `import something`, Python searches a list of directories stored in `sys.path`:

```python theme={null}
import sys
print(sys.path)  # The list of places Python checks
```

The search order is:

1. The folder containing the script you ran
2. Python's built-in standard library folders
3. Installed third-party packages in `site-packages`

## Absolute vs relative imports

When working inside a package, you can import modules in two ways:

```python theme={null}
# Absolute import — uses the full path from the project root
from mypackage.utils import format_text

# Relative import — uses dots to navigate relative to the current file
from .utils import format_text    # . means current directory
from ..core import database       # .. means parent directory
```

<Warning>
  **Always prefer absolute imports.** They're clearer, less fragile, and won't break if you move a file. Relative imports also cause a confusing error if you run the file directly as a script:

  `ImportError: attempted relative import with no known parent package`
</Warning>

## Package initialization: `__init__.py` and `__all__`

A directory becomes a Python package when it contains an `__init__.py` file. This file runs automatically when the package is imported. You can control what gets exposed publicly using `__all__`:

```python theme={null}
# mypackage/__init__.py
# Only expose 'utils' when someone does: from mypackage import *
__all__ = ["utils"]
```

## The `__name__ == "__main__"` pattern

When Python runs a file directly, it sets the special variable `__name__` to `"__main__"`. When that same file is imported by another script, `__name__` is set to the module's actual name instead. Use this to write code that only runs when the file is executed directly:

```python theme={null}
# calculator.py

def add(a, b):
    return a + b

# This block is skipped when another script does: import calculator
if __name__ == "__main__":
    print("Testing calculator...")
    print(add(10, 5) == 15)  # True
```

## Running modules and fixing import errors

### The scenario

```text theme={null}
myproject/
├── main.py
└── mypackage/
    ├── utils.py
    └── helper.py
```

Inside `utils.py`: `from mypackage.helper import greet`

### The mistake

If you navigate into `mypackage/` and run `python utils.py`, Python crashes with:

```text theme={null}
ModuleNotFoundError: No module named 'mypackage'
```

Python adds the directory of the *executed script* to `sys.path`. It sees `mypackage/` — not `myproject/` — so it doesn't know `mypackage` exists one level up.

### The solutions

<Steps>
  <Step title="Solution 1 — Run as a module with -m (Recommended)">
    Always run from the **project root** using the `-m` flag:

    ```bash theme={null}
    # Navigate to the project root
    cd myproject

    # Run using dot notation (no .py extension)
    python -m mypackage.utils
    ```

    This preserves the package hierarchy and configures `sys.path` correctly.
  </Step>

  <Step title="Solution 2 — Set PYTHONPATH">
    Tell Python where the project root is:

    <CodeGroup>
      ```bash macOS/Linux theme={null}
      export PYTHONPATH=.
      python mypackage/utils.py
      ```

      ```powershell Windows theme={null}
      $env:PYTHONPATH="."
      python mypackage/utils.py
      ```
    </CodeGroup>
  </Step>
</Steps>

## Adding folders to Python's search path manually

Sometimes you need Python to look in an extra location:

```python theme={null}
import sys
import os

# Add a specific folder
sys.path.append("/path/to/my/folder")

# Add the parent folder of the current script
parent = os.path.dirname(os.path.dirname(__file__))
sys.path.append(parent)
```

## Common mistakes

<AccordionGroup>
  <Accordion title="FileNotFoundError: No such file or directory">
    Python can't find your data file. The path is wrong or you're running from an unexpected directory.

    ```python theme={null}
    import os
    print("Looking in:", os.getcwd())
    print("Files here:", os.listdir())
    ```

    Fix: Use the correct relative path from `os.getcwd()`, or use an absolute path.
  </Accordion>

  <Accordion title="ModuleNotFoundError: No module named 'X'">
    Python can't find the module you're importing.

    ```python theme={null}
    import sys
    print("Python searches:", sys.path)
    ```

    Fix: Make sure the module's directory is in `sys.path`, or use the `-m` flag to run from the project root.
  </Accordion>

  <Accordion title="Mixing up files and modules">
    ```python theme={null}
    # Wrong — you can't use slashes in import statements
    import data/helpers   # SyntaxError!

    # Right — use dots for module imports
    import data.helpers   # Imports data/helpers.py
    ```
  </Accordion>

  <Accordion title="Running from the wrong folder">
    ```python theme={null}
    import os
    print("Running from:", os.getcwd())
    ```

    Fix: Navigate to the correct directory in your terminal, or use the VS Code Play button (it always runs from the file's directory).
  </Accordion>

  <Accordion title="Backslashes on macOS/Linux">
    ```python theme={null}
    # Works on every platform
    "data/file.csv"

    # Only works on Windows
    "data\\file.csv"
    ```

    Always use forward slashes in path strings — they work everywhere.
  </Accordion>
</AccordionGroup>

## Keep it simple

Everyone hits path confusion at first. For now:

* Keep related files in the same folder whenever possible
* Use the VS Code Play button — it's predictable
* When confused, print `os.getcwd()` immediately to see where Python is looking
* Run scripts from the project root using `python -m` for anything involving packages

<Card title="Organizing code" icon="arrow-right" href="/practical-python/organizing-code">
  Split your code into reusable functions and files
</Card>
