python-packages-cheatsheet

Modules and packages

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

Publishing a package

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",

        ]

    },

)