skip to content

Packaging and Environments

Where Python looks for your code and how you hand it to someone else: import machinery, isolated environments and lockfiles, and the artifacts you publish. Import errors and dependency conflicts cost teams days.

part ofPythonoverview, primer and where to startread it →
on this pageshow

explore

questions

118 · 4 sections

In Python, what is the difference between an absolute import and a relative import?

level: juniorimportance: must knowfreq 62%
basics
~20 s

An absolute import spells out the full dotted path from an import root, such as from app.core import config. An explicit relative import starts with dots that count outward from the importing module's own package: from . import config.

open as a page

What does Python's ImportError 'cannot import name X from partially initialized module' mean?

level: juniorimportance: must knowfreq 58%
basics
~10 s

Two modules import each other. Python began running the first one, cached it half-finished, and the second one asked it for a name that has not been defined yet, so the name lookup fails.

open as a page

What does the if __name__ == "__main__": guard at the end of a Python file do?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Python sets the module global name to "main" only in the file the interpreter was started with; an imported module gets its dotted import name instead. The guarded block therefore runs on direct execution and is skipped on import.

open as a page

What distinguishes a Python package from a plain module, and what does __init__.py do?

level: juniorimportance: must knowfreq 70%
basics
~20 s

A module is one importable unit of code, usually a single .py file. A package is a module that can also contain submodules: a directory whose init.py file is executed as the package's own body when it is first imported.

open as a page

Why does a Python directory with no __init__.py still import as a package?

level: juniorimportance: must knowfreq 45%
basics
~20 s

Since Python 3.3 (PEP 420) a directory with no init.py imports as an implicit namespace package: the search path held only matching directories, so Python builds a package that runs no code and whose file is None.

open as a page

What does `pip install -e .` do that a plain `pip install .` does not?

level: juniorimportance: must knowfreq 62%
basics
~20 s

pip install -e . installs the project in editable mode: site-packages receives a pointer back to your working source tree instead of a copy of it, so a source edit takes effect on the next interpreter start without reinstalling.

open as a page

Why can `python -m pip install` and a bare `pip install` target different interpreters?

level: juniorimportance: must knowfreq 62%
basics
~20 s

A bare pip is a script on PATH whose shebang points at whichever interpreter installed it, so PATH order decides where the install lands. python -m pip runs the pip belonging to the interpreter you just named, so the packages land where that interpreter imports from.

open as a page

Why does pyproject.toml declare dependency ranges while a deployed requirements.txt pins exact versions?

level: juniorimportance: must knowfreq 68%
basics
~10 s

pyproject.toml declares abstract dependencies: the ranges a package can work with, re-resolved at install time. A pinned requirements.txt records one concrete resolution so a particular deployment installs exactly the same versions every time.

open as a page

What can `pip install` take as a target besides a package name from PyPI?

level: juniorimportance: must knowfreq 68%
basics
~20 s

Besides a name from an index, pip install accepts a path to a project directory, wheel or sdist, a direct URL, a version-control reference such as git+https at a tag or commit, and -r to read requirement lines from a file.

open as a page

What does an all-in-one Python project manager add on top of pip and venv?

level: juniorimportance: must knowfreq 58%
basics
~20 s

It owns the project end to end: it creates and syncs a project-local virtual environment, resolves the declared dependencies into a lock file, and runs commands inside that environment. pip and venv each do one piece and leave the wiring to you.

open as a page

What does a `[project.scripts]` entry in pyproject.toml create when the package is installed?

level: juniorimportance: must knowfreq 60%
basics
~20 s

It declares a console command. At install time the installer generates a small wrapper in the environment's script directory that imports the named module and calls the named function, so typing the command runs your code.

open as a page

What does `pip install mypkg[redis]` do, and where is that extra declared?

level: juniorimportance: must knowfreq 55%
basics
~20 s

It installs mypkg itself plus the optional dependency set named redis. That set is declared in the project's pyproject.toml under the [project.optional-dependencies] table, where each key is an extra name and its value is a list of requirement strings.

open as a page

Why does pip compile a package with a C extension from source, and what does that build need?

level: juniorimportance: must knowfreq 55%
basics
~20 s

Because no prebuilt wheel matched this machine's interpreter version, ABI and platform, pip fell back to the source archive. Compiling it needs a C compiler and linker, CPython's development headers (Python.h), and the project's declared build backend.

open as a page

How do you ship a JSON schema file inside your Python package's wheel?

level: juniorimportance: must knowfreq 55%
basics
~20 s

Put the file inside the importable package directory and declare it as package data in your build backend's configuration. Setuptools needs a package-data entry, or include-package-data together with MANIFEST.in; hatchling and flit ship non-code files under the package by default.

open as a page

What does a single leading underscore on a Python module or class attribute name mean?

level: juniorimportance: must knowfreq 62%
basics
~20 s

A single leading underscore marks a name as internal: not part of the public API and free to change without notice. It is a convention, not enforcement — outside code can still import and call it.

open as a page

Why does Python hide DeprecationWarning by default, and how do you surface it?

level: juniorimportance: must knowfreq 55%
basics
~20 s

Python's default filters ignore DeprecationWarning unless it is attributed to the main module, so end users are not flooded with warnings about libraries they did not write. Surface them with -W default::DeprecationWarning, PYTHONWARNINGS, or -X dev.

open as a page

What does requires-python in pyproject.toml do when an old interpreter installs your package?

level: middleimportance: must knowfreq 55%
basics
~20 s

It declares the interpreter range the distribution supports, and lands in the built metadata as Requires-Python. An installer filters out releases whose range excludes the running interpreter and resolves to the newest release that still allows it.

open as a page

How do you use sys.version_info to guard code that only runs on newer Python?

level: juniorimportance: should knowfreq 45%
basics
~10 s

Compare sys.version_info against a plain tuple, as in sys.version_info >= (3, 12), and put the newer-only import or branch inside that guard. Never parse the sys.version string; tuple comparison is exact, cheap and unambiguous.

open as a page

How do you make a CI run fail on DeprecationWarning without breaking on third-party ones?

level: middleimportance: should knowfreq 45%
basics
~20 s

Promote the category to an error, but scope it. Run the suite with -W ignore::DeprecationWarning -W error::DeprecationWarning:yourpackage, or set PYTHONWARNINGS to the same spec: the later filter is checked first, so only your own code is fatal.

open as a page

How do you stage a migration off stdlib modules PEP 594 removed before an upgrade?

level: seniorimportance: should knowfreq 32%
basics
~20 s

Do the diagnosis on the interpreter you are leaving: PEP 387 guarantees two releases of DeprecationWarning, but it is filtered out by default. Surface it, diff your imports against the target's sys.stdlib_module_names, then replace modules one at a time before bumping the interpreter.

open as a page