In code
1
breakpoint()
Command line interface
1
python -m pdb --help
Might need to reinstall only python-minimal, reinstall other packages as needed.
1
apt-get install --reinstall python python-minimal python-setuptools
Option to protect against accidental invocation on import of a file. Better to write clean modules to import but this way is common in python.
1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env python
def is_tool(name):
"""Check if `name` is on PATH and is executable."""
from shutil import which
return which(name) is not None
if __name__ == '__main__':
"""Main code protected from accidental invocation."""
tool = "ping"
if is_tool(tool):
print("We have ping")
A script imported without this if __name__ == '__main__': guard block will be triggered by the importing script:
This is almost always a mistake.
If there is a custom class in the guardless script and it is saved to a pickle file, then unpickling it in another script will trigger an import of the guardless script, with the same problems.
1 is the lowest priority (last group on the line).
1
2
#update-alternatives --install /usr/bin/python python /usr/bin/python3 2
#update-alternatives --install /usr/bin/python python /usr/bin/python2 1
Install
1
2
aptitude install python3 python3-pip python3-venv
Creation of the virtual environment:
1
python3 -m venv django-venv
Getting an error like
1
ImportError: cannot import name 'Popen' from partially initialized module 'subprocess' (most likely due to a circular import)
could mean you have a file named subprocess.py in the directory you're in. Any python module names being used as a file name will probably trigger this. It'll make python try to override its module and find the "module" in your file is not a module.
Create and end the session you'll be installing your app in:
1
2
source bin/activate
(django-venv)deactivate
Preparation in the session:
1
python3 -m pip install --upgrade pip
Install your app:
1
python3 -m pip install django
or
1
python3 -m pip install django~=1.10.4
for version matching.
https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/
Some packages have optional extras. You can tell pip to install these by specifying the extra in brackets:
1
python3 -m pip install requests[security]
python3 -m pip can install a package directly from source, for example:
1
2
cd google-auth
python3 -m pip install .
Additionally, pip can install packages from source in development mode, meaning that changes to the source directory will immediately affect the installed package without needing to re-install:
1
python3 -m pip install --editable .
python3 -m pip can install packages directly from their version control system. For example, you can install directly from a git repository:
1
git+https://github.com/GoogleCloudPlatform/google-auth-library-python.git#egg=google-auth
For more information on supported version control systems and syntax, see pip’s documentation on VCS Support.
If you have a local copy of a Distribution Package’s archive (a zip, wheel, or tar file) you can install it directly with pip:
1
python3 -m pip install requests-2.18.4.tar.gz
If you have a directory containing archives of multiple packages, you can tell pip to look for packages there and not to use the Python Package Index (PyPI) at all:
1
python3 -m pip install --no-index --find-links=/local/dir/ requests
This is useful if you are installing packages on a system with limited connectivity or if you want to strictly control the origin of distribution packages.
If you want to download packages from a different index than the Python Package Index (PyPI), you can use the –index-url flag:
1
python3 -m pip install --index-url http://index.example.com/simple/ SomeProject
If you want to allow packages from both the Python Package Index (PyPI) and a separate index, you can use the –extra-index-url flag instead:
1
python3 -m pip install --extra-index-url http://index.example.com/simple/ SomeProject
Instead of installing packages individually, pip allows you to declare all dependencies in a Requirements File. For example you could create a requirements.txt file containing:
1
2
requests==2.18.4
google-auth==1.1.0
And tell pip too install all of the packages in this file using the -r flag:
1
python3 -m pip install -r requirements.txt
Constraints files are in the format of requirements. They control which version of a package can be installed but provide no control over the actual installation. For example, a production environment can have hardened versions of packages specified via constraints.
1
2
python -m pip -c constraints.txt
PIP_CONSTRAINTS='https://example.com/constraints.txt' python -m pip
Pip can export a list of all installed packages and their versions using the freeze command:
1
python3 -m pip freeze
Which will output a list of package specifiers such as:
1
2
3
4
5
6
7
8
9
10
11
cachetools==2.0.1
certifi==2017.7.27.1
chardet==3.0.4
google-auth==1.1.1
idna==2.6
pyasn1==0.3.6
pyasn1-modules==0.1.4
requests==2.18.4
rsa==3.4.2
six==1.11.0
urllib3==1.22
This is useful for creating Requirements Files that can re-create the exact versions of all packages installed in an environment.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/usr/bin/env python3
# %z not supported in python2
# Delete backup files by entity, determine entity from the file name. Successful backups must be larger than size, smaller are not counted. At least 3 successful backups kept (warning if first older than 35 days), no more than 3 if older than 21 days.
import glob, os
import time
import datetime
last = "" # entity's last backup
count = 0 # entity's count of backups
cur_timestamp = time.time()
timeformat = "%Y%m%d%H%M%S%z"
for infile in sorted(glob.glob('./*.tar.gz'), reverse=True):
filename = infile[:-7]
entity = filename[:-19]
date1 = filename[-19:]
file_info = os.stat(infile)
size = file_info.st_size
if (entity != last): # new entity
count = 0
last = entity
print( str(entity) + ":----------" )
if (size > 50000): count+=1
timestamp = time.mktime(datetime.datetime.strptime(date1, timeformat).timetuple())
age = int((cur_timestamp-timestamp)//60/60/24) # file's age in days
print( str(count) + ": " + entity + " " + date1 + " size: " + str(size) + " age: "+ str(age) + " d." )
if (age > 21 and count > 3):
print( "rm: count: " + str(count) + ", age " + str(age) + ": " + infile)
os.remove(infile)
elif (age > 35):
print( str(count) + ": " + str(age) + " days old, " + entity + " " + date1 + " " + infile )
Debugging is enabled by default in python.
A docstring is the first line of a module, function, class, or method definition.
Docstrings, formatted like git commit messages, are removed when using python -OO
1
2
3
4
5
6
def printTruth():
r"""This method prints truth.
This is a raw docstring in case there's a \
in the docstring."""
print("True")
1
print(printTruth.__doc__)
An assert statement and any code conditional on the value of __debug__ is removed with python -O
1
assert age == 2
is equivalent to
1
2
if __debug__:
if not age == 2: raise AssertionError
Append when adding a single element, extend when adding all elements of a list.
1
2
3
4
5
6
7
8
9
10
11
12
result = [
"This list will contain",
]
s = "all elements of the list a: "
a = [
"fox",
"wolf",
"bear",
]
result.append(s)
result.extend(a)
print(result)
Old package format used by setuptools was egg. Left from that era is the directory name suffix .egg-info.
1
2
3
4
5
6
7
example_project.egg-info/
├── dependency_links.txt
├── entry_points.txt
├── PKG-INFO
├── requires.txt
├── SOURCES.txt
└── top_level.txt
Current package format is wheel .whl.
Modern packages are declared in pyproject.toml. This allows selecting a build system and replaces setup.py.
Historical setuptools convention dictated using __init__.py to mark a python package. There were 3 schools of thought.
__init__.py blank. This enforces explicit imports and thus clear namespaces.Minimal setup.py that can be used with pyproject.toml for compatibility.
1
2
3
import setuptools
setuptools.setup()
Sample repository structure using uv.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
├── docs
│ └── sample.md
├── LICENSE
├── pyproject.toml
├── .python-version
├── README.md
├── requirements.txt
├── src
│ └── sample
│ ├── __init__.py
│ ├── sample.py
│ └── helpers.py
├── tests
│ └── test.py
└── uv.lock
Supports Jinja2 templates to customize output. Main use case for pdoc is API documentation, more complex needs are better served by Sphinx.
1
2
pdoc --help
pdoc ./demo.py -o ./docs
Variables are not assigned the __doc__ attribute by python. pdoc will read the abstract syntax tree (an abstract representation of the source code) and include all assignment statements immediately followed by a docstring.
The public interface (API) of a module is determined through one of two ways.
__all__ is defined in the module, then all identifiers in that list will be considered public. No other identifiers will be considered public.__all__ is not defined, then pdoc will consider all items public that do not start with an underscore and that are defined in the current module (i.e. they are not imported).If you want to override the default behavior for a particular item, you can do so by including an annotation in its docstring:
@private hides an item unconditionally.@public shows an item unconditionally.Pdoc is meant to be compatible with the autodoc extension for Sphinx.
1
2
3
4
5
6
7
# docs/conf.py
extensions = [
...
'sphinx.ext.autodoc',
'myst_parser', # markdown support for sphinx
]
Info fields can be added to docstrings for Sphinx.
1
2
3
4
5
def my_function(*args):
"""Example function
:meta private:
"""
1
2
3
4
5
uv init hello
uv version --bump patch --bump dev --dry-run
uv lock --upgrade-package requests
uv help venv
uv build
Initialize a package, moves code to src/ directory and defines a build system.
1
uv init --package hello
Inline script metadata according to PEP 723.
1
2
3
4
5
6
7
#!/usr/bin/env -S uv run
# /// script
# requires-python = ">=3.13"
# dependencies = [
# "biopython",
# ]
# ///
1
2
uv export --no-hashes --format requirements-txt --output-file requirements.txt
uv add -r requirements.txt
Same process as in python packaging guide, using an entry point to create spam-cli.
1
2
3
# pyproject.toml
[project.scripts]
spam-cli = "spam:main_cli"
effectively does
1
2
3
import sys
from spam import main_cli
sys.exit(main_cli())