source: realpython
module search path
directory from where input script is run
PYTHONPATH
environment variable
accessible via sys.path
from the sys
module (use sys.path.append(r'some_absolute_path')
to update the import search path)
from module import *
is poor practice as it can overwrite conflicting names (it imports everything except any object that starts with an underscore)
built-in function dir()
return list of defined names in the namespace (variables, modules, functions, etc...)
to execute module as script, place instructions under statement if __name__ == '__main__'
(__name__
is called a dunder variable)
use builtin library importlib
to reload a module: importlib.reload(mod)
a package is a directory containing several modules. When a __init__.py
file is present in package directory, it is invoked when the package or one of its module is imported.
simply calling import pkg
will not place any of the modules in the local namespace (therefore pkg.mod1
or pkg.mod2
will throw an error)
in order to use import pkg
, the modules have to be called in the __init__.py
file (import pkg.mod1, pkg.mod2
)
to determine what from pkg import *
imports, specify the __all__ = ['mod1', 'mod2']
variable in the __init__.py
file.
packages can contain nested subpackages to arbitrary depth (folders of modules inside the package folder)
to call siblings modules within a package, one can use either absolute or relative imports but relative imports only work when the module is called as a module and not executed as a script
source: realpython
running a package (i.e. a directory) as a script with -m
flag executes the contents of the __main__.py
file
importlib.resources
is used to import non-code files from a package without having to worry about full file path. Useful when the code doesn't sit on the filesystem (don't fiddle with the __file__
attribute as the code will break when served from a zip)
PyPI name of the package doesn't have to be the same as the package name (it has to be unique among PyPI packages)
information about the package is contained in setup.py
file. Some parameters:
name (as it will appear on PyPI)
version: MAJOR (make incompatible API changes).MINOR (add functionality in a backwards-compatible manner).PATCH (backwards-compatible bug fixes) (e.g. 0.1.2); PyPI will only let you do one upload of a particular version for a package
packages: takes list of packages and subpackages; use setuptools.find_packages()
to discover all subpackages
install_requires: list any dependencies (same as in requirements.txt
to avoid double dependency issue)
entry_points: used to create scripts that call a function within a package
long_description: assign to README to display it on PyPI
PyPI packages are distributed as python wheels or source archives (tar file) as opposed to plain source code. To create a source archive and a wheel, run: python setup.py sdist bdist_wheel
(creates two files in dist
directory)
register PyPI account (and TestPyPI account for testing before publishing) and upload using twine upload dist/*
(can specify test url). twine is installed via pip install twine
new tools for publishing packages use pyproject.toml
configuration file
Example of setup.py
file:
import pathlib
from setuptools import setup
# The directory containing this file
HERE = pathlib.Path(__file__).parent
# The text of the README file
README = (HERE / "README.md").read_text()
# This call to setup() does all the work
setup(
name="realpython-reader",
version="1.0.0",
description="Read the latest Real Python tutorials",
long_description=README,
long_description_content_type="text/markdown",
url="https://github.com/realpython/reader",
author="Real Python",
author_email="[email protected]",
license="MIT",
classifiers=[
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
],
packages=["reader"],
include_package_data=True,
install_requires=["feedparser", "html2text"],
entry_points={
"console_scripts": [
"realpython=reader.__main__:main",
]
},
)