How to create a Python library
Ever wanted to create a Python library, albeit for your team at work or for some open source project online? In this blog you will learn how to!
The tutorial is easiest to follow when you are using the same tools, however it is also possible for you to use different ones.
The tools used in this tutorial are:
— Linux command prompt
— Visual Studio Code
Step 1: Create a directory in which you want to put your library
Open your command prompt and create a folder in which you will create your Python library.
Remember:
— With pwd you can see your present working directory.
— With ls you can list the folders and files in your directory.
— With cd <path> you can change the current present directory you are in.
— With mkdir <folder> you can create a new folder in your working directory.
In my case, the folder I will be working with is mypythonlibrary . Change the present working directory to be your folder.
Step 2: Create a virtual environment for your folder
When starting your project, it is always a good idea to create a virtual environment to encapsulate your project. A virtual environment consists of a certain Python version and some libraries.
Virtual environments prevent the issue of running into dependency issues later on. For example, in older projects you might have worked with older versions of the numpy library. Some old code, that once worked beautifully, might stop working once you update its version. Perhaps parts of numpy are no longer compatible with other parts of your program. Creating virtual environments prevents this. They are also useful in cases when you are collaborating with someone else, and you want to make sure that your application is working on their computer, and vice versa.
(Make sure you changed the present working directory to the folder you are going to create your Python library in ( cd <path/to/folder> ).)
Go ahead and create a virtual environment by typing:
> python3 -m venv venv
Once it is created, you must now activate the environment by using:
> source venv/bin/activate
Activating a virtual environment modifies the PATH and shell variables to point to the specific isolated Python set-up you created. PATH is an environmental variable in Linux and other Unix-like operating systems that tells the shell which directories to search for executable files (i.e., ready-to-run programs) in response to commands issued by a user. The command prompt will change to indicate which virtual environment you are currently in by prepending ( yourenvname ).
In your environment, make sure you have pip installed wheel , setuptools and twine . We will need them for later to build our Python library.
> pip install wheel
> pip install setuptools
> pip install twine
Step 3: Create a folder structure
In Visual Studio Code, open your folder mypythonlibrary (or any name you have given your folder). It should look something like this:
You now can start adding folders and files to your project. You can do this either through the command prompt or in Visual Studio Code itself.
- Create an empty file called setup.py . This is one of the most important files when creating a Python library!
- Create an empty file called README.md . This is the place where you can write markdown to describe the contents of your library for other users.
- Create a folder called mypythonlib , or whatever you want your Python library to be called when you pip install it. (The name should be unique on pip if you want to publish it later.)
- Create an empty file inside mypythonlib that is called __init__.py . Basically, any folder that has an __init__.py file in it, will be included in the library when we build it. Most of the time, you can leave the __init__.py files empty. Upon import, the code within __init__.py gets executed, so it should contain only the minimal amount of code that is needed to be able to run your project. For now, we will leave them as is.
- Also, in the same folder, create a file called myfunctions.py .
- And, finally, create a folder tests in your root folder. Inside, create an empty __init__.py file and an empty test_myfunctions.py .
Your set-up should now look something like this:
Step 4: Create content for your library
To put functions inside your library, you can place them in the myfunctions.py file. For example, copy the haversine function in your file:
This function will give us the distance in meters between two latitude and longitude points.
Whenever you write any code, it is highly encouraged to also write tests for this code. For testing with Python you can use the libraries pytest and pytest-runner . Install the library in your virtual environment:
> pip install pytest==4.4.1
> pip install pytest-runner==4.4
Let’s create a small test for the haversine function. Copy the following and place it inside the test_myfunctions.py file:
Finally, let’s create a setup.py file, that will help us to build the library. A limited version of setup.py will look something like this:
The name variable in setup holds whatever name you want your package wheel file to have. To make it easy, we will gave it the same name as the folder.
Set the packages you would like to create
While in principle you could use find_packages() without any arguments, this can potentially result in unwanted packages to be included. This can happen, for example, if you included an __init__.py in your tests/ directory (which we did). Alternatively, you can also use the exclude argument to explicitly prevent the inclusion of tests in the package, but this is slightly less robust. Let’s change it to the following:
Set the requirements your library needs
Note that pip does not use requirements.yml / requirements.txt when your project is installed as a dependency by others. Generally, for that, you will have to specify dependencies in the install_requires and tests_require arguments in your setup.py file.
Install_requires should be limited to the list of packages that are absolutely needed. This is because you do not want to make users install unnecessary packages. Also note that you do not need to list packages that are part of the standard Python library.
However, since we have only defined the haversine function so far and it only uses the math library (which is always available in Python), we can leave this argument empty.
Maybe you can remember us installing the pytest library before. Of course, you do not want to add pytest to your dependencies in install_requires : it isn’t required by the users of your package. In order to have it installed automatically only when you run tests you can add the following to your setup.py :
Running:
> python setup.py pytest
will execute all tests stored in the ‘tests’ folder.
Step 5: Build your library
Now that all the content is there, we want to build our library. Make sure your present working directory is /path/to/mypythonlibrary (so the root folder of your project). In your command prompt, run:
> python setup.py bdist_wheel
Your wheel file is stored in the “dist” folder that is now created. You can install your library by using:
> pip install /path/to/wheelfile.whl
Note that you could also publish your library to an internal file system on intranet at your workplace, or to the official PyPI repository and install it from there.
Once you have installed your Python library, you can import it using:
import mypythonlib
from mypythonlib import myfunctions
Как создать свой первый open source проект на Python (17 шагов)
Каждый разработчик ПО должен знать как создать библиотеку с нуля. В процессе работы Вы можете многому научиться. Только не забудьте запастись временем и терпением.
Может показаться, что создать библиотеку с открытым исходным кодом сложно, но Вам не нужно быть потрепанным жизнью ветераном своего дела, чтобы разобраться в коде. Также как Вам не нужна мудреная идея продукта. Но точно понадобятся настойчивость и время. Надеюсь, что данное руководство поможет Вам создать первый проект с минимальной затратой и первого, и второго.
В этой статье мы пошагово разберем процесс создания базовой библиотеки на Python. Не забудьте заменить в приведенном ниже коде my_package, my_file и т.п. нужными вам именами.
Шаг 1: Составьте план
Мы планируем создать простую библиотеку для использования в Python. Данная библиотека позволит пользователю легко конвертировать блокнот Jupyter в HTML-файл или Python-скрипт.
Первая итерация нашей библиотеки позволит вызвать функцию, которая выведет определенное сообщение.
Теперь, когда мы уже знаем, что хотим делать, нужно придумать название для библиотеки.
Шаг 2: Дайте имя библиотеке
Придумывать имена сложно. Они должны быть короткими, уникальными и запоминающимися. Также они должны быть написаны строчными буквами, без прочерков и прочих знаков препинания. Подчеркивание не рекомендуется. В процессе создания библиотеки убедитесь, что придуманное Вами имя доступно на GitHub, Google и PyPi.
Если Вы надеетесь и верите, что однажды Ваша библиотека получит 10000 звезд GitHub, то стоит проверить, доступно ли данное имя в социальных сетях. В данном примере я назову свою библиотеку notebookc, потому что это имя доступное, короткое и более-менее описывает суть моей задумки.
Шаг 3. Настройте среду
Убедитесь, что у вас установлены и настроены Python 3.7, GitHub и Homebrew. Если вам нужно что-то из этого, вот подробности:
Python
Скачайте Python 3.7 здесь и установите его.
GitHub
Если у вас нет учетной записи GitHub, перейдите по этой ссылке и оформите бесплатную подписку. Посмотрите, как установить и настроить Git здесь. Вам потребуется утилита командной строки. Перейдите по ссылкам, скачайте и установите все, что Вам понадобится, придумайте юзернейм и укажите электронную почту.
Homebrew
Homebrew — менеджер библиотек для Mac. Инструкции по установке найдете здесь.
Начиная с Python 3.6 рекомендуется использовать venv для создания виртуальной среды для разработки библиотек. Существует множество способов управления виртуальными средами с помощью Python и все они со временем изменяются. Можете ознакомиться с обсуждением здесь, но, как говорится, доверяй, но проверяй.
Начиная с версии Python 3.3 venv входит в систему по умолчанию. Обратите внимание, что venv устанавливает pip и setuptools начиная с Python 3.4.
Создайте виртуальную среду Python 3.7 с помощью следующей команды:
python3.7 -m venv my_env
Замените my_env вашим именем. Активируйте среду таким образом:
Теперь вы должны наблюдать (my_env) (или имя, которое вы выбрали для вашей виртуальной среды) в крайнем левом углу терминала.
Когда закончите работу, деактивируйте виртуальную среду с помощью deactivate .
Теперь давайте настроим GitHub.
Шаг 4: Создайте организацию в GitHub
GitHub — лидер на рынке реестров контроля версий. Еще две популярные опции — GitLab и Bitbucket. В данном гиде мы будем использовать именно GitHub.
Вам придется часто обращаться к Git и GitHub, поэтому если Вы не знакомы с системой, то можете обратиться к моей статье.
Создайте новую организацию в GitHub. Следуйте инструкциям. Я назвал свою организацию notebooktoall. Вы можете создать репозиторий под своей личной учетной записью, но одна из целей работы — научиться создавать проект с открытым исходным кодом для более широкого сообщества.

Шаг 5: Настройте GitHub Repo
Создайте новый репозиторий. Я назвал свой notebookc.

Добавьте .gitignore из выпадающего списка. Выберите Python для своего репозитория. Содержимое Вашего файла .gitignore будет соответствовать папкам и типам файлов, исключенным из вашего хранилища. Вы можете позже изменить .gitignore, чтобы исключить другие ненужные или конфиденциальные файлы.
Рекомендую выбрать лицензию в списке Выбрать лицензию. Она определяет, что могут делать пользователи Вашего репозитория. Одни лицензии позволяют больше других. Если Вы ничего не выбираете, то автоматически начинают действовать стандартные законы об авторских правах. Узнайте больше о лицензиях здесь.
Для этого проекта я выбрал третью версию Открытого лицензионного соглашения GNU, потому что она популярная, проверенная и “гарантирует пользователям свободу использования, изучения, обмена и изменения программного обеспечения” — источник.

Шаг 6: Клонируйте и добавьте директории
Выберите, куда Вы хотите клонировать Ваш репозиторий или выполните следующую функцию:
git clone https://github.com/notebooktoall/notebookc.git
Подставьте свою организацию и репозиторий.
Перейдите в папку проекта с помощью десктопного графического интерфейса или редактора кода. Или используйте командную строку с cd my-project и после просмотрите файлы с ls —A .
Ваши исходные папки и файлы должны выглядеть так:
.git
.gitignore
LICENSE
README.rst
Создайте вложенную папку для основных файлов проекта. Я советую назвать ее так же, как и вашу библиотеку. Убедитесь, что в имени нет пробелов.
Создайте файл с именем __init__.py в основной вложенной папке. Этот файл пока останется пустым. Он необходим для импорта файлов.
Создайте еще один файл с таким же именем, как у основной вложенной папки, и добавьте .py. Мой файл называется notebookc.py. Вы можете назвать этот Python-файл как захотите. Пользователи библиотеки при импорте модуля будут ссылаться на имя этого файла.
Содержимое моей директории notebookc выглядит следующим образом:
.git
.gitignore
LICENSE
README.rst
notebookc/__init__.py
notebookc/notebookc.py
Шаг 7: Скачайте и установите requirements_dev.txt
На верхнем уровне директории проекта создайте файл requirements_dev.txt. Часто этот файл называют requirements.txt. Назвав его requirements_dev.txt, Вы показываете, что эти библиотеки могут устанавливаться только разработчиками проекта.
В файле укажите, что должны быть установлены pip и wheel.
Обратите внимание, что мы указываем точные версии библиотек с двойными знаками равенства и полными номерами версии.
Закрепите версии вашей библиотеку в requirements_dev.txt
Соавтор, который разветвляет репозиторий проекта и устанавливает закрепленные библиотеки require_dev.txt с помощью pip, будет иметь те же версии библиотеки, что и Вы. Вы знаете, что эта версия будет работать у них. Кроме того, Read The Docs будет использовать этот файл для установки библиотек при сборке документации.
В вашей активированной виртуальной среде установите библиотеку в файл needs_dev.txt с помощью следующей команды:
pip install -r requirements_dev.txt
Настоятельно рекомендую обновлять эти библиотеки по мере выхода новых версий. На данный момент установите любые последние версии, доступные на PyPi.
В следующей статье расскажу, как установить инструмент, облегчающий этот процесс. Подпишитесь, чтобы не пропустить.
Шаг 8: Поработайте с кодом
В целях демонстрации давайте создадим базовую функцию. Свою собственную крутую функцию сможете создать позже.
Вбейте следующее в Ваш основной файл (для меня это notebookc/notebookc/notebookc.py):
Вот наша функция во всей красе.
Строки документа начинаются и заканчиваются тремя последовательными двойными кавычками. Они будут использованы в следующей статье для автоматического создания документации.
Сохраните изменения. Если хотите освежить память о работе с Git, то можете заглянуть в эту статью.
Шаг 9: Создайте setup.py
Файл setup.py — это скрипт сборки для вашей библиотеки. Функция setup из Setuptools создаст библиотеку для загрузки в PyPI. Setuptools содержит информацию о вашей библиотеке, номере версии и о том, какие другие библиотеки требуются для пользователей.
Вот мой пример файла setup.py:
Обратите внимание, что long_description установлен на содержимое файла README.md. Список требований (requirements), указанный в setuptools.setup.install_requires, включает в себя все необходимые зависимости для работы вашей библиотеки.
В отличие от списка библиотек, требуемых для разработки в файле require_dev.txt, этот список должен быть максимально разрешающим. Узнайте почему здесь.
Ограничьте список install_requires только тем, что Вам надо — Вам не нужно, чтобы пользователи устанавливали лишние библиотеки. Обратите внимание, что необходимо только перечислить те библиотеки, которые не являются частью стандартной библиотеки Python. У Вашего пользователя и так будет установлен Python, если он будет использовать вашу библиотеку.
Наша библиотека не требует никаких внешних зависимостей, поэтому Вы можете исключить четыре библиотеки, перечисленных в примере выше.
Соавтор, который разветвляет репозиторий проекта и устанавливает закрепленные библиотеки с помощью pip, будет иметь те же версии, что и Вы. Это значит, что они должны работать.
Измените информацию setuptools так, чтобы она соответствовала информации вашей библиотеки. Существует множество других необязательных аргументов и классификаторов ключевых слов — см. перечень здесь. Более подробные руководства по setup.py можно найти здесь и здесь.
Сохраните свой код в локальном репозитории Git. Пора переходить к созданию библиотеки!
Шаг 10: Соберите первую версию
Twine — это набор утилит для безопасной публикации библиотек Python на PyPI. Добавьте библиотеку Twine в следующую пустую строку файла require_dev.txt таким образом:
Затем закрепите Twine в Вашей виртуальной среде, переустановив библиотеки needs_dev.txt.
Затем выполните следующую команду, чтобы создать файлы библиотеки:
Необходимо создать несколько скрытых папок: dist, build и — в моем случае — notebookc.egg-info. Давайте посмотрим на файлы в папке dist. Файл .whl — это файл Wheel — встроенный дистрибутив. Файл .tar.gz является исходным архивом.
На компьютере пользователя pip будет по мере возможности устанавливать библиотеки как wheels/колеса. Они устанавливаются быстрее. Когда pip не может этого сделать, он возвращается к исходному архиву.
Давайте подготовимся к загрузке нашего колеса и исходного архива.
Шаг 11: Создайте учётную запись TestPyPI
PyPI — каталог библиотек Python (Python Package Index). Это официальный менеджер библиотек Python. Если файлы не установлены локально, pip получает их оттуда.
TestPyPI — это работающая тестовая версия PyPI. Создайте здесь учетную запись TestPyPI и подтвердите адрес электронной почты. Обратите внимание, что у Вас должны быть отдельные пароли для загрузки на тестовый сайт и официальный сайт.
Шаг 12: Опубликуйте библиотеку в PyPI
Используйте Twine для безопасной публикации вашей библиотеки в TestPyPI. Введите следующую команду — никаких изменений не требуется.
Вам будет предложено ввести имя пользователя и пароль. Не забывайте, что TestPyPI и PyPI имеют разные пароли!
При необходимости исправьте все ошибки, создайте новый номер версии в файле setup.py и удалите старые артефакты сборки: папки build, dist и egg. Перестройте задачу с помощью python setup.py sdist bdist_wheel и повторно загрузите с помощью Twine. Наличие номеров версий в TestPyPI, которые ничего не значат, особой роли не играют — Вы единственный, кто будет использовать эти версии библиотек.
После того, как Вы успешно загрузили свою библиотеку, давайте удостоверимся, что Вы можете установить его и использовать.
Шаг 13: Проверьте и используйте установленную библиотеку
Создайте еще одну вкладку в командном интерпретаторе и запустите другую виртуальную среду.
Если Вы уже загрузили свою библиотеку на официальный сайт PyPI, то сможете выполнить команду pip install your-package . Мы можем извлечь библиотеку из TestPyPI и установить его с помощью измененной команды.
Вот официальные инструкции по установке вашей библиотеки из TestPyPI:
Вы можете заставить pip загружать библиотеки из TestPyPI вместо PyPI, указав это в index-url.
Если хотите, чтобы pip также извлекал и другие библиотеки из PyPI, Вы можете добавить — extra-index-url для указания на PyPI. Это полезно, когда тестируемая библиотека имеет зависимости:
Если у вашей библиотеки есть зависимости, используйте вторую команду и подставьте имя вашей библиотеки.
Вы должны увидеть последнюю версию библиотеки, установленного в Вашей виртуальной среде.
Чтобы убедиться, что Вы можете использовать свою библиотеку, запустите сеанс IPython в терминале следующим образом:
Импортируйте свою функцию и вызовите ее со строковым аргументом. Вот как выглядит мой код:
После я получаю следующий вывод:
(Когда-нибудь я конвертирую для тебя блокнот, Джефф)
Шаг 14: Залейте код на PyPI
Залейте Ваш код на настоящий сайт PyPI, чтобы люди могли скачать его с помощью pip install my_package .
Загрузить код можно так:
Обратите внимание, что Вам нужно обновить номер версии в setup.py, если Вы хотите залить новую версию в PyPI.
Отлично, теперь давайте загрузим нашу работу на GitHub.
Шаг 15: Залейте библиотеку на GitHub
Убедитесь, что Ваш код сохранен.
Моя папка проекта notebookc выглядит так:
Исключите любые виртуальные среды, которые Вы не хотите загружать. Файл Python .gitignore, который мы выбрали при создании репозитория, не должен допускать индексации артефактов сборки. Возможно, Вам придется удалить папки виртуальной среды.
Переместите вашу локальную ветку на GitHub с помощью git push origin my_branch .
Шаг 16: Создайте и объедините PR
В браузере перейдите к GitHub. У Вас должна появиться опция сделать pull-запрос. Нажимайте на зеленые кнопки, чтобы создать, объединить PR и чтобы убрать удаленную ветку.
Вернувшись в терминал, удалите локальную ветку с git branch -d my_feature_branch .
Шаг 17: Обновите рабочую версию на GitHub
Создайте новую версию библиотеки на GitHub, кликнув на релизы на главной странице репозитория. Введите необходимую информацию о релизе и сохраните.
На сегодня достаточно!
Мы научимся добавлять другие файлы и папки в будущих статьях.
А пока давайте повторим шаги, которые мы разобрали.
Итог: 17 шагов к рабочей библиотеке
- Составьте план.
- Дайте имя библиотеке.
- Настройте среду.
- Создайте организацию в GitHub.
- Настройте GitHub Repo.
- Клонируйте и добавьте директории.
- Скачайте и установите requirements_dev.txt.
- Поработайте с кодом.
- Создайте setup.py.
- Соберите первую версию.
- Создайте учётную запись TestPyPI.
- Опубликуйте библиотеку в PyPI.
- Проверьте и используйте установленную библиотеку.
- Залейте код на PyPI.
- Залейте библиотеку на GitHub.
- Создайте и объедините PR.
- Обновите рабочую версию на GitHub.
Узнайте подробности, как получить востребованную профессию с нуля или Level Up по навыкам и зарплате, пройдя платные онлайн-курсы SkillFactory:
Глава 16. Создание пакетов библиотек
Вы хотите выпустить скрипт, библиотеку, фреймворк или приложение на Python? Превосходно. Миру нужно больше кода на Python. Python 3 поставляется с системой создания пакетов Distutils. Distutils – это много всего: инструмент сборки (для вас), инструмент установки (для ваших пользователей), формат метаданных пакета (для поисковых систем) и многое другое. Он интегрирован с каталогом пакетов Python PyPI, центральным репозиторием библиотек Python с открытым исходным кодом.
Все эти аспекты Distutils сосредоточены вокруг сценария установки, который обычно называется setup.py . На самом деле, вы уже видели в этой книге несколько скриптов установки Distutils. Вы использовали Distutils для установки httplib2 в HTTP веб-сервисах и еще раз для установки chardet в главе 15 «Учебный пример: портирование chardet на Python 3».
В данной главе вы узнаете, как работают скрипты установки для chardet и httplib2 , и пройдете через процесс релиза своего собственного программного обеспечения на Python.
chardet и httplib2 имеют открытый исходный код, но нет требований, под какой-либо конкретной лицензией вам выпускать собственные библиотеки на Python. Процесс, описанный в данной главе, будет работать для любого программного обеспечения на Python, независимо от лицензии.
16.2 Вещи, которые Distutils не может сделать за вас
Релиз вашего первого пакета Python – сложный процесс (релиз второго немного проще). Distutils пытается максимально автоматизировать его, но есть некоторые вещи, которые вы просто должны сделать сами.
- Выбрать лицензию. Это сложная тема, связанная с политикой и опасностями. Если вы хотите выпустить свое программное обеспечение с открытым исходным кодом, я скромно предлагаю пять советов:
- Не пишите свою собственную лицензию.
- Не пишите свою собственную лицензию.
- Не пишите свою собственную лицензию.
- Это не обязательно должен быть GPL, но она должна быть GPL-совместимой.
- Не пишите свою собственную лицензию.
- Классифицировать свое программное обеспечение, используя систему классификации PyPI. Я объясню, что это значит позже в этой главе.
- Написать файл «прочти меня» (read me). Не экономьте на этом. Как минимум, он должен дать вашим пользователям обзор того, что делает ваше программное обеспечение и как его установить.
16.3 Структура каталогов
Чтобы начать создавать пакет программного обеспечения на Python, вам нужно привести в порядок файлы и каталоги. Каталог httplib2 выглядит так:
- Создайте корневой каталог для хранения всего. Дайте ему то же имя, что и вашему модулю на Python.
- Для удобства пользователей Windows ваш файл «readme» должен иметь расширение .txt и использовать символ возврата каретки. То, что вы используете нестандартный текстовый редактор, который запускается из командной строки и включает в себя собственный язык макросов, не означает, что вам нужно усложнить жизнь своим пользователям (ваши пользователи используют Notepad; грустно но это так). Даже если вы работаете в Linux или Mac OS X, ваш модный текстовый редактор, несомненно, имеет возможность сохранять файлы, используя символы возврата каретки в стиле Windows.
- Ваш скрипт Distutils для установки должен называться setup.py , если у вас нет веских причин так не делать. У вас нет веских причин так не делать.
- Если ваше программное обеспечение на Python представляет собой один файл .py , вы должны поместить его в корневой каталог вместе с файлом «readme» и скриптом установки. Но httplib2 – это не один файл .py; это многофайловый модуль. Но это нормально! Просто поместите каталог httplib2 в корневой каталог, чтобы у вас был файл __init__.py в каталоге httplib2/ в корневом каталоге httplib2/ . Это не проблема; на самом деле это упростит процесс упаковки.
Каталог chardet выглядит немного иначе. Как и httplib2 , это многофайловый модуль, поэтому в корневом каталоге chardet/ находится каталог chardet/ . В дополнение к файлу README.txt , chardet содержит документацию в формате HTML в каталоге docs/ . Каталог docs/ содержит несколько файлов .html и .css и подкаталог images/ , который содержит несколько файлов .png и .gif (это будет важно позднее). Также, в соответствии с соглашением для (L)GPL-лицензированного программного обеспечения, у него есть отдельный файл с именем COPYING.txt , который содержит полный текст LGPL.
16.4 Написание скрипта установки
Скрипт установки Distutils – это скрипт на Python. Теоретически, он может делать всё, что может делать Python. На практике он должен быть как можно меньше, и как можно более стандартным. Скрипты установки должны быть скучными. Чем более экзотичен процесс установки, тем более экзотичны будут ваши сообщения об ошибках.
Первая строка каждого скрипта установки Distutils всегда одинакова:
Это импортирует функцию setup() , которая является основной точкой входа в Distutils. 95% всех скриптов установки Distutils состоят из одного вызова setup() , и ничего более. (Я только что придумал эту статистику, но если ваш скрипт установки Distutils делает больше, чем просто вызывает функцию Distutils setup() , у вас должна быть веская причина. У вас есть веская причина? Не думаю.)
Функция setup() может принимать десятки параметров. Чтобы все вовлеченные участники понимали, о чем идет речь, для каждого параметра вы должны использовать именованные аргументы. Это не просто соглашение; это обязательное требование. Ваш скрипт установки завершится сбоем, если вы попытаетесь вызвать функцию setup() с неименованными аргументами.
Следующие именованные аргументы обязательны:
- name , название пакета;
- version , номер версии пакета;
- author , ваше полное имя;
- author_email , ваш адрес электронной почты;
- url , домашняя страница вашего проекта. Если у вас нет отдельного веб-сайта для проекта, то это может быть ваша страница пакета на PyPI,.
Хотя это и не обязательно, я рекомендую также включить в скрипт установки следующее:
- description , однострочное описание проекта.
- long_description , многострочное описание в формате reStructuredText. PyPI преобразует его в HTML и покажет его на странице вашего пакета.
- classifiers , список специально отформатированных строк, описанных в следующем разделе.
Метаданные скрипта установки определены в PEP 314.
Теперь давайте посмотрим на скрипт установки chardet . В нем есть все эти обязательные и рекомендуемые параметры, плюс один, который я еще не упомянул: packages .
Параметр packages указывает на неудачное совпадение слов в процессе создания дистрибутива. Мы говорим о «пакете» как о том, что вы создаете (и, возможно, включаете его в Python “Package” Index). Но этот параметр packages относится не к этому. Он относится к тому факту, что модуль chardet является многофайловым модулем, иногда называемым… «пакетом». Параметр packages указывает Distutils включить каталог chardet/ , его файл __init__.py и все другие файлы .py , которые составляют модуль chardet . Это очень важно; все эти счастливые разговоры о документации и метаданных не имеют значения, если вы забудете включить реальный код!
16.5 Классификация вашего пакета
Python Package Index (PyPI) содержит тысячи библиотек на Python. Правильные метаданные классификации упростят людям поиск ваших проектов. PyPI позволяет просматривать пакеты по классификатору. Вы даже можете выбрать несколько классификаторов, чтобы сузить область поиска. Классификаторы – это не невидимые метаданные, которые вы можете просто игнорировать!
Чтобы классифицировать ваше программное обеспечение, передайте параметр classifiers функции setup() Distutils. Параметр classifiers представляет собой список строк. Эти строки не являются произвольными. Все строки классификатора должны браться из этого списка на PyPI.
Классификаторы необязательны. Вы можете написать скрипт установки Distutils без каких-либо классификаторов вообще. Но не делайте так. Вы должны всегда включать, по крайней мере, следующие классификаторы:
- Programming Language (язык программирования). В частности, вы должны включить и " Programming Language :: Python ", и " Programming Language :: Python :: 3 ". Если вы не включите их, ваш пакет не будет отображаться в этом списке библиотек, совместимых с Python 3.
- License (лицензия). Это первое, на что я обращаю внимание при оценке сторонних библиотек. Не заставляйте меня охотиться за этой важной информацией. Не включайте более одного классификатора лицензии, если ваше программное обеспечение явно не доступно под несколькими лицензиями. (И не выпускайте программное обеспечение под несколькими лицензиями, если не обязаны это делать. И не заставляйте других людей делать это. Лицензирование – достаточная головная боль; не усугубляйте еще больше.)
- Operating System (операционная система). Если ваше программное обеспечение работает только в Windows (или Mac OS X, или Linux), я хочу узнать об этом раньше, а не позже. Если ваше программное обеспечение работает везде без какого-либо платформозависимого кода, используйте классификатор " Operating System :: OS Independent ". Несколько классификаторов Operating System необходимы только в том случае, если вашему программному обеспечению требуется конкретная поддержка для каждой платформы (это не распространено).
Я также рекомендую вам включить следующие классификаторы:
- Development Status (состояние разработки). Ваше программное обеспечение в версии бета? В версии альфа? Пре-альфа? Выбери один из вариантов. Будьте честны.
- Intended Audience (целевая аудитория). Кто будет загружать ваше программное обеспечение? Наиболее распространенными вариантами являются Developers (разработчики), End Users/Desktop (конечные пользователи / десктоп), Science/Research (наука/исследования) and System Administrators (системные администраторы).
- Framework (фреймворк). Если ваше программное обеспечение является плагином для более крупного фреймворка Python, такого как Django или Zope, включите соответствующий классификатор Framework . Если нет, пропустите его.
- Topic (тема). Есть большое количество тем на выбор; выберите всё, что подходит.
16.5.1 Примеры хороших классификаторов пакетов
В качестве примера, вот классификаторы для Django, готового к работе, кроссплатформенного, лицензированного под BSD фреймворка веб-приложений, который работает на вашем веб-сервере.
Вот классификаторы для chardet , библиотеки определения кодировки символов, описанной в главе 15 «Учебный пример: портирование chardet на Python 3». chardet – в бета-версии, кроссплатформенная, совместимая с Python 3, лицензия LGPL, и предназначена для разработчиков, чтобы интегрировать в свои собственные продукты.
А вот классификаторы для httplib2 , библиотеки, представленной в главе 14 «HTTP веб-сервисы». httplib2 – в бета-версии, кроссплатформенная, с лицензией MIT, предназначена для разработчиков на Python.
16.6 Указание дополнительных файлов с помощью манифеста
По умолчанию Distutils будет включать в ваш пакет следующие файлы:
- README.txt
- setup.py
- Файлы .py , необходимые для многофайловых модулей, перечисленных в параметре packages
- Отдельные .py файлы, перечисленные в параметре py_modules
Это охватывает все файлы в проекте httplib2 . Но для проекта chardet мы также хотим включить файл лицензии COPYING.txt и весь каталог docs/ , содержащий изображения и HTML файлы. Чтобы указать Distutils, чтобы он при сборке пакета chardet включил эти дополнительные файлы и каталоги, вам понадобится файл манифеста.
Файл манифеста – это текстовый файл с именем MANIFEST.in . Поместите его в корневой каталог проекта, рядом с README.txt и setup.py . Файлы манифеста – это не скрипты Python; это текстовые файлы, которые содержат серию «команд» в формате, определенном Distutils. Команды манифеста позволяют включать или исключать определенные файлы и каталоги.
Это весь файл манифеста для проекта chardet :
- Строка 1. Первая строка не требует пояснений: включить файл COPYING.txt из корневого каталога проекта.
- Строка 2. Вторая строка немного сложнее. Команда recursive-include принимает имя каталога и одно или несколько имен файлов. Имена файлов не ограничены конкретными файлами; они могут включать подстановочные знаки. Эта строка означает «Видите этот каталог docs/ в корневом каталоге проекта? Ищите там (рекурсивно) файлы .html , .css , .png и .gif . Я хочу, чтобы все они были в релизе моего пакета.»
Все команды манифеста сохраняют структуру каталогов, заданную вами в каталоге вашего проекта. Эта команда recursive-include не собирается помещать кучу файлов .html и .png в корневой каталог выпускаемого пакета. Она сохранит существующую структуру каталога docs/ , но включая в себя только те файлы в этом каталоге, которые соответствуют заданным подстановочным символам. (Я не упоминал об этом ранее, но документация chardet на самом деле написана в формате XML и преобразована в HTML отдельным скриптом. Я не хочу включать файлы XML в релиз пакета, мне нужны только HTML и изображения.)
Файлы манифеста имеют свой уникальный формат. Для получения подробной информации смотрите определение файлов для распространения и шаблоны команд манифеста.
Повторим: вам нужно создавать файл манифеста, только если вы хотите включить файлы, которые Distutils не включает по умолчанию. Если вам нужен файл манифеста, он должен включать только те файлы и каталоги, которые Distutils не смог бы найти самостоятельно.
16.7 Проверка вашего скрипта установки на наличие ошибок
Есть много чего, что нужно отслеживать. Distutils поставляется со встроенной командой проверки, которая проверяет в вашем скрипте установки наличие всех необходимых метаданных. Например, если вы забудете включить параметр version , Distutils напомнит вам.
После того, как вы добавите параметр version (и все остальные необходимые метаданные), результат команды check будет выглядеть следующим образом:
16.8 Создание дистрибутива исходников
Distutils поддерживает сборку различных типов пакетов. Как минимум, вы должны создать «дистрибутив исходников», который содержит ваш исходный код, ваш скрипт установки Distutils, ваш файл «read me» и все дополнительные файлы, которые вы хотите включить. Чтобы создать дистрибутив исходников, передайте в ваш скрипт установки Distutils команду sdist .
- Distutils заметил файл манифеста ( MANIFEST.in ).
- Distutils успешно проанализировал файл манифеста и добавил нужные нам файлы: COPYING.txt , а также HTML файлы и изображения в каталоге docs/ .
- Если вы загляните в каталог вашего проекта, вы увидите, что Distutils создал каталог dist/ . В этом каталоге dist/ находится .zip -файл, который вы можете распространять.
16.9 Создание графического установщика
По-моему, каждая библиотека Python заслуживает наличие графического установщика для пользователей Windows. Его легко обеспечить (даже если вы сами не работаете под Windows), а пользователи Windows это ценят.
Distutils может создать для вас графический установщик Windows, если передадите в ваш скрипт установки Distutils команду bdist_wininst .
16.9.1 Сборка устанавливаемых пакетов для других операционных систем
Distutils может помочь вам создать устанавливаемые пакеты для пользователей Linux. На мой взгляд, возможно, это не стоит вашего времени. Если вы хотите, чтобы ваше программное обеспечение распространялось для Linux, вам лучше было бы потратить время на работу с членами сообщества, которые специализируются на создании пакетов программного обеспечения для основных дистрибутивов Linux.
Например, моя библиотека chardet находится в репозиториях Debian GNU/Linux (и, следовательно, в репозиториях Ubuntu). Я не имел ничего общего с этим; пакеты просто появились там однажды. Сообщество Debian имеет свои собственные политики для создания пакетов библиотек Python, а пакет Debian python-chardet разработан в соответствии с этими соглашениями. А поскольку пакет находится в репозиториях Debian, пользователи Debian будут получать обновления безопасности и/или новые версии в зависимости от общесистемных настроек, выбранных ими для управления своими компьютерами.
Пакеты Linux, которые собирает Distutils, не предлагают ни одно из этих преимуществ. Лучше потратить время на что-то другое.
16.10 Добавление вашего программного обеспечения в Python Package Index
Загрузка программного обеспечения в Python Package Index состоит из трех этапов.
- зарегистрируетесь сами;
- зарегистрируйте свое программное обеспечение;
- загрузите пакеты, которые вы создали с помощью setup.py sdist и setup.py bdist_ * .
Чтобы зарегистрироваться, перейдите на страницу регистрации пользователя PyPI. Введите имя пользователя и пароль, укажите действующий адрес электронной почты и нажмите кнопку « Create account ». (Если у вас есть ключ PGP или GPG, можете также предоставить его. Если у вас его нет или вы не знаете, что это такое, то не беспокойтесь об этом.) Проверьте свою электронную почту; в течение нескольких минут вы получите сообщение от PyPI со ссылкой для проверки. Нажмите на ссылку, чтобы завершить процесс регистрации.
Теперь вам нужно зарегистрировать свое программное обеспечение в PyPI и загрузить его. Вы можете сделать всё это за один шаг.
- Строка 1. Когда вы публикуете свой проект впервые, Distutils добавит ваше программное обеспечение в Python Package Index и присвоит ему собственный URL. Каждый раз после этого он будет просто обновлять метаданные проекта с любыми изменениями, которые вы могли внести в параметры setup.py . Затем он создает дистрибутив исходного кода ( sdist ) и установщик Windows ( bdist_wininst ), а затем загружает их в PyPI ( upload ).
- Строка 8. Введите 1 или просто нажмите ENTER , чтобы выбрать «использовать существующий логин».
- Строка 9. Введите имя пользователя и пароль, которые вы выбрали на странице регистрации пользователя PyPI. Distuils не будет выводить ваш пароль; он даже не будет отражать звездочки вместо символов. Просто введите свой пароль и нажмите клавишу ENTER .
- Строка 11. Distutils регистрирует ваш пакет в Python Package Index…
- Строка 13. … собирает ваш дистрибутив исходного кода…
- Строка 15. … собирает ваш установщик Windows…
- Строка 17. … и загружает их обоих в Python Package Index.
- Строка 24. Если вы хотите автоматизировать процесс релиза новых версий, то вам нужно сохранить свои учетные данные PyPI в локальном файле. Это совершенно небезопасно и совершенно необязательно.
Поздравляем, теперь у вас есть собственная страница в Python Package Index! Ее адрес: http://pypi.python.org/pypi/NAME , где NAME – это строка, которую вы передали в параметре name в файле setup.py .
Если вы хотите выпустить новую версию, просто обновите в вашем файле setup.py номер версии, а затем снова выполните ту же команду загрузки:
16.11 Множество возможных вариантов создания пакетов Python
Distutils не является единственным инструментом создания пакетов Python, но на момент написания этой статьи (август 2009 года) это единственный фреймворк создания пакетов, который работает в Python 3. Существует ряд других платформ для Python 2; некоторые фокусируются на установке, другие – на тестировании и развертывании. Некоторые или все из них могут в конечном итоге быть перенесены на Python 3 в будущем.
1. Extending Python with C or C++¶
It is quite easy to add new built-in modules to Python, if you know how to program in C. Such extension modules can do two things that can’t be done directly in Python: they can implement new built-in object types, and they can call C library functions and system calls.
To support extensions, the Python API (Application Programmers Interface) defines a set of functions, macros and variables that provide access to most aspects of the Python run-time system. The Python API is incorporated in a C source file by including the header "Python.h" .
The compilation of an extension module depends on its intended use as well as on your system setup; details are given in later chapters.
The C extension interface is specific to CPython, and extension modules do not work on other Python implementations. In many cases, it is possible to avoid writing C extensions and preserve portability to other implementations. For example, if your use case is calling C library functions or system calls, you should consider using the ctypes module or the cffi library rather than writing custom C code. These modules let you write Python code to interface with C code and are more portable between implementations of Python than writing and compiling a C extension module.
1.1. A Simple Example¶
Let’s create an extension module called spam (the favorite food of Monty Python fans…) and let’s say we want to create a Python interface to the C library function system() 1. This function takes a null-terminated character string as argument and returns an integer. We want this function to be callable from Python as follows:
Begin by creating a file spammodule.c . (Historically, if a module is called spam , the C file containing its implementation is called spammodule.c ; if the module name is very long, like spammify , the module name can be just spammify.c .)
The first two lines of our file can be:
which pulls in the Python API (you can add a comment describing the purpose of the module and a copyright notice if you like).
Since Python may define some pre-processor definitions which affect the standard headers on some systems, you must include Python.h before any standard headers are included.
It is recommended to always define PY_SSIZE_T_CLEAN before including Python.h . See Extracting Parameters in Extension Functions for a description of this macro.
All user-visible symbols defined by Python.h have a prefix of Py or PY , except those defined in standard header files. For convenience, and since they are used extensively by the Python interpreter, "Python.h" includes a few standard header files: <stdio.h> , <string.h> , <errno.h> , and <stdlib.h> . If the latter header file does not exist on your system, it declares the functions malloc() , free() and realloc() directly.
The next thing we add to our module file is the C function that will be called when the Python expression spam.system(string) is evaluated (we’ll see shortly how it ends up being called):
There is a straightforward translation from the argument list in Python (for example, the single expression "ls -l" ) to the arguments passed to the C function. The C function always has two arguments, conventionally named self and args.
The self argument points to the module object for module-level functions; for a method it would point to the object instance.
The args argument will be a pointer to a Python tuple object containing the arguments. Each item of the tuple corresponds to an argument in the call’s argument list. The arguments are Python objects — in order to do anything with them in our C function we have to convert them to C values. The function PyArg_ParseTuple() in the Python API checks the argument types and converts them to C values. It uses a template string to determine the required types of the arguments as well as the types of the C variables into which to store the converted values. More about this later.
PyArg_ParseTuple() returns true (nonzero) if all arguments have the right type and its components have been stored in the variables whose addresses are passed. It returns false (zero) if an invalid argument list was passed. In the latter case it also raises an appropriate exception so the calling function can return NULL immediately (as we saw in the example).
1.2. Intermezzo: Errors and Exceptions¶
An important convention throughout the Python interpreter is the following: when a function fails, it should set an exception condition and return an error value (usually -1 or a NULL pointer). Exception information is stored in three members of the interpreter’s thread state. These are NULL if there is no exception. Otherwise they are the C equivalents of the members of the Python tuple returned by sys.exc_info() . These are the exception type, exception instance, and a traceback object. It is important to know about them to understand how errors are passed around.
The Python API defines a number of functions to set various types of exceptions.
The most common one is PyErr_SetString() . Its arguments are an exception object and a C string. The exception object is usually a predefined object like PyExc_ZeroDivisionError . The C string indicates the cause of the error and is converted to a Python string object and stored as the “associated value” of the exception.
Another useful function is PyErr_SetFromErrno() , which only takes an exception argument and constructs the associated value by inspection of the global variable errno . The most general function is PyErr_SetObject() , which takes two object arguments, the exception and its associated value. You don’t need to Py_INCREF() the objects passed to any of these functions.
You can test non-destructively whether an exception has been set with PyErr_Occurred() . This returns the current exception object, or NULL if no exception has occurred. You normally don’t need to call PyErr_Occurred() to see whether an error occurred in a function call, since you should be able to tell from the return value.
When a function f that calls another function g detects that the latter fails, f should itself return an error value (usually NULL or -1 ). It should not call one of the PyErr_* functions — one has already been called by g. f’s caller is then supposed to also return an error indication to its caller, again without calling PyErr_* , and so on — the most detailed cause of the error was already reported by the function that first detected it. Once the error reaches the Python interpreter’s main loop, this aborts the currently executing Python code and tries to find an exception handler specified by the Python programmer.
(There are situations where a module can actually give a more detailed error message by calling another PyErr_* function, and in such cases it is fine to do so. As a general rule, however, this is not necessary, and can cause information about the cause of the error to be lost: most operations can fail for a variety of reasons.)
To ignore an exception set by a function call that failed, the exception condition must be cleared explicitly by calling PyErr_Clear() . The only time C code should call PyErr_Clear() is if it doesn’t want to pass the error on to the interpreter but wants to handle it completely by itself (possibly by trying something else, or pretending nothing went wrong).
Every failing malloc() call must be turned into an exception — the direct caller of malloc() (or realloc() ) must call PyErr_NoMemory() and return a failure indicator itself. All the object-creating functions (for example, PyLong_FromLong() ) already do this, so this note is only relevant to those who call malloc() directly.
Also note that, with the important exception of PyArg_ParseTuple() and friends, functions that return an integer status usually return a positive value or zero for success and -1 for failure, like Unix system calls.
Finally, be careful to clean up garbage (by making Py_XDECREF() or Py_DECREF() calls for objects you have already created) when you return an error indicator!
The choice of which exception to raise is entirely yours. There are predeclared C objects corresponding to all built-in Python exceptions, such as PyExc_ZeroDivisionError , which you can use directly. Of course, you should choose exceptions wisely — don’t use PyExc_TypeError to mean that a file couldn’t be opened (that should probably be PyExc_IOError ). If something’s wrong with the argument list, the PyArg_ParseTuple() function usually raises PyExc_TypeError . If you have an argument whose value must be in a particular range or must satisfy other conditions, PyExc_ValueError is appropriate.
You can also define a new exception that is unique to your module. For this, you usually declare a static object variable at the beginning of your file:
and initialize it in your module’s initialization function ( PyInit_spam() ) with an exception object:
Note that the Python name for the exception object is spam.error . The PyErr_NewException() function may create a class with the base class being Exception (unless another class is passed in instead of NULL ), described in Built-in Exceptions .
Note also that the SpamError variable retains a reference to the newly created exception class; this is intentional! Since the exception could be removed from the module by external code, an owned reference to the class is needed to ensure that it will not be discarded, causing SpamError to become a dangling pointer. Should it become a dangling pointer, C code which raises the exception could cause a core dump or other unintended side effects.
We discuss the use of PyMODINIT_FUNC as a function return type later in this sample.
The spam.error exception can be raised in your extension module using a call to PyErr_SetString() as shown below:
1.3. Back to the Example¶
Going back to our example function, you should now be able to understand this statement:
It returns NULL (the error indicator for functions returning object pointers) if an error is detected in the argument list, relying on the exception set by PyArg_ParseTuple() . Otherwise the string value of the argument has been copied to the local variable command . This is a pointer assignment and you are not supposed to modify the string to which it points (so in Standard C, the variable command should properly be declared as const char *command ).
The next statement is a call to the Unix function system() , passing it the string we just got from PyArg_ParseTuple() :
Our spam.system() function must return the value of sts as a Python object. This is done using the function PyLong_FromLong() .
In this case, it will return an integer object. (Yes, even integers are objects on the heap in Python!)
If you have a C function that returns no useful argument (a function returning void ), the corresponding Python function must return None . You need this idiom to do so (which is implemented by the Py_RETURN_NONE macro):
Py_None is the C name for the special Python object None . It is a genuine Python object rather than a NULL pointer, which means “error” in most contexts, as we have seen.
1.4. The Module’s Method Table and Initialization Function¶
I promised to show how spam_system() is called from Python programs. First, we need to list its name and address in a “method table”:
Note the third entry ( METH_VARARGS ). This is a flag telling the interpreter the calling convention to be used for the C function. It should normally always be METH_VARARGS or METH_VARARGS | METH_KEYWORDS ; a value of 0 means that an obsolete variant of PyArg_ParseTuple() is used.
When using only METH_VARARGS , the function should expect the Python-level parameters to be passed in as a tuple acceptable for parsing via PyArg_ParseTuple() ; more information on this function is provided below.
The METH_KEYWORDS bit may be set in the third field if keyword arguments should be passed to the function. In this case, the C function should accept a third PyObject * parameter which will be a dictionary of keywords. Use PyArg_ParseTupleAndKeywords() to parse the arguments to such a function.
The method table must be referenced in the module definition structure:
This structure, in turn, must be passed to the interpreter in the module’s initialization function. The initialization function must be named PyInit_name() , where name is the name of the module, and should be the only non- static item defined in the module file:
Note that PyMODINIT_FUNC declares the function as PyObject * return type, declares any special linkage declarations required by the platform, and for C++ declares the function as extern "C" .
When the Python program imports module spam for the first time, PyInit_spam() is called. (See below for comments about embedding Python.) It calls PyModule_Create() , which returns a module object, and inserts built-in function objects into the newly created module based upon the table (an array of PyMethodDef structures) found in the module definition. PyModule_Create() returns a pointer to the module object that it creates. It may abort with a fatal error for certain errors, or return NULL if the module could not be initialized satisfactorily. The init function must return the module object to its caller, so that it then gets inserted into sys.modules .
When embedding Python, the PyInit_spam() function is not called automatically unless there’s an entry in the PyImport_Inittab table. To add the module to the initialization table, use PyImport_AppendInittab() , optionally followed by an import of the module:
Removing entries from sys.modules or importing compiled modules into multiple interpreters within a process (or following a fork() without an intervening exec() ) can create problems for some extension modules. Extension module authors should exercise caution when initializing internal data structures.
A more substantial example module is included in the Python source distribution as Modules/xxmodule.c . This file may be used as a template or simply read as an example.
Unlike our spam example, xxmodule uses multi-phase initialization (new in Python 3.5), where a PyModuleDef structure is returned from PyInit_spam , and creation of the module is left to the import machinery. For details on multi-phase initialization, see PEP 489.
1.5. Compilation and Linkage¶
There are two more things to do before you can use your new extension: compiling and linking it with the Python system. If you use dynamic loading, the details may depend on the style of dynamic loading your system uses; see the chapters about building extension modules (chapter Building C and C++ Extensions ) and additional information that pertains only to building on Windows (chapter Building C and C++ Extensions on Windows ) for more information about this.
If you can’t use dynamic loading, or if you want to make your module a permanent part of the Python interpreter, you will have to change the configuration setup and rebuild the interpreter. Luckily, this is very simple on Unix: just place your file ( spammodule.c for example) in the Modules/ directory of an unpacked source distribution, add a line to the file Modules/Setup.local describing your file:
and rebuild the interpreter by running make in the toplevel directory. You can also run make in the Modules/ subdirectory, but then you must first rebuild Makefile there by running ‘make Makefile’. (This is necessary each time you change the Setup file.)
If your module requires additional libraries to link with, these can be listed on the line in the configuration file as well, for instance:
1.6. Calling Python Functions from C¶
So far we have concentrated on making C functions callable from Python. The reverse is also useful: calling Python functions from C. This is especially the case for libraries that support so-called “callback” functions. If a C interface makes use of callbacks, the equivalent Python often needs to provide a callback mechanism to the Python programmer; the implementation will require calling the Python callback functions from a C callback. Other uses are also imaginable.
Fortunately, the Python interpreter is easily called recursively, and there is a standard interface to call a Python function. (I won’t dwell on how to call the Python parser with a particular string as input — if you’re interested, have a look at the implementation of the -c command line option in Modules/main.c from the Python source code.)
Calling a Python function is easy. First, the Python program must somehow pass you the Python function object. You should provide a function (or some other interface) to do this. When this function is called, save a pointer to the Python function object (be careful to Py_INCREF() it!) in a global variable — or wherever you see fit. For example, the following function might be part of a module definition:
This function must be registered with the interpreter using the METH_VARARGS flag; this is described in section The Module’s Method Table and Initialization Function . The PyArg_ParseTuple() function and its arguments are documented in section Extracting Parameters in Extension Functions .
The macros Py_XINCREF() and Py_XDECREF() increment/decrement the reference count of an object and are safe in the presence of NULL pointers (but note that temp will not be NULL in this context). More info on them in section Reference Counts .
Later, when it is time to call the function, you call the C function PyObject_CallObject() . This function has two arguments, both pointers to arbitrary Python objects: the Python function, and the argument list. The argument list must always be a tuple object, whose length is the number of arguments. To call the Python function with no arguments, pass in NULL , or an empty tuple; to call it with one argument, pass a singleton tuple. Py_BuildValue() returns a tuple when its format string consists of zero or more format codes between parentheses. For example:
PyObject_CallObject() returns a Python object pointer: this is the return value of the Python function. PyObject_CallObject() is “reference-count-neutral” with respect to its arguments. In the example a new tuple was created to serve as the argument list, which is Py_DECREF() -ed immediately after the PyObject_CallObject() call.
The return value of PyObject_CallObject() is “new”: either it is a brand new object, or it is an existing object whose reference count has been incremented. So, unless you want to save it in a global variable, you should somehow Py_DECREF() the result, even (especially!) if you are not interested in its value.
Before you do this, however, it is important to check that the return value isn’t NULL . If it is, the Python function terminated by raising an exception. If the C code that called PyObject_CallObject() is called from Python, it should now return an error indication to its Python caller, so the interpreter can print a stack trace, or the calling Python code can handle the exception. If this is not possible or desirable, the exception should be cleared by calling PyErr_Clear() . For example:
Depending on the desired interface to the Python callback function, you may also have to provide an argument list to PyObject_CallObject() . In some cases the argument list is also provided by the Python program, through the same interface that specified the callback function. It can then be saved and used in the same manner as the function object. In other cases, you may have to construct a new tuple to pass as the argument list. The simplest way to do this is to call Py_BuildValue() . For example, if you want to pass an integral event code, you might use the following code:
Note the placement of Py_DECREF(arglist) immediately after the call, before the error check! Also note that strictly speaking this code is not complete: Py_BuildValue() may run out of memory, and this should be checked.
You may also call a function with keyword arguments by using PyObject_Call() , which supports arguments and keyword arguments. As in the above example, we use Py_BuildValue() to construct the dictionary.
1.7. Extracting Parameters in Extension Functions¶
The PyArg_ParseTuple() function is declared as follows:
The arg argument must be a tuple object containing an argument list passed from Python to a C function. The format argument must be a format string, whose syntax is explained in Parsing arguments and building values in the Python/C API Reference Manual. The remaining arguments must be addresses of variables whose type is determined by the format string.
Note that while PyArg_ParseTuple() checks that the Python arguments have the required types, it cannot check the validity of the addresses of C variables passed to the call: if you make mistakes there, your code will probably crash or at least overwrite random bits in memory. So be careful!
Note that any Python object references which are provided to the caller are borrowed references; do not decrement their reference count!
Some example calls:
1.8. Keyword Parameters for Extension Functions¶
The PyArg_ParseTupleAndKeywords() function is declared as follows:
The arg and format parameters are identical to those of the PyArg_ParseTuple() function. The kwdict parameter is the dictionary of keywords received as the third parameter from the Python runtime. The kwlist parameter is a NULL -terminated list of strings which identify the parameters; the names are matched with the type information from format from left to right. On success, PyArg_ParseTupleAndKeywords() returns true, otherwise it returns false and raises an appropriate exception.
Nested tuples cannot be parsed when using keyword arguments! Keyword parameters passed in which are not present in the kwlist will cause TypeError to be raised.
Here is an example module which uses keywords, based on an example by Geoff Philbrick (philbrick @ hks . com):
1.9. Building Arbitrary Values¶
This function is the counterpart to PyArg_ParseTuple() . It is declared as follows:
It recognizes a set of format units similar to the ones recognized by PyArg_ParseTuple() , but the arguments (which are input to the function, not output) must not be pointers, just values. It returns a new Python object, suitable for returning from a C function called from Python.
One difference with PyArg_ParseTuple() : while the latter requires its first argument to be a tuple (since Python argument lists are always represented as tuples internally), Py_BuildValue() does not always build a tuple. It builds a tuple only if its format string contains two or more format units. If the format string is empty, it returns None ; if it contains exactly one format unit, it returns whatever object is described by that format unit. To force it to return a tuple of size 0 or one, parenthesize the format string.
Examples (to the left the call, to the right the resulting Python value):
1.10. Reference Counts¶
In languages like C or C++, the programmer is responsible for dynamic allocation and deallocation of memory on the heap. In C, this is done using the functions malloc() and free() . In C++, the operators new and delete are used with essentially the same meaning and we’ll restrict the following discussion to the C case.
Every block of memory allocated with malloc() should eventually be returned to the pool of available memory by exactly one call to free() . It is important to call free() at the right time. If a block’s address is forgotten but free() is not called for it, the memory it occupies cannot be reused until the program terminates. This is called a memory leak. On the other hand, if a program calls free() for a block and then continues to use the block, it creates a conflict with re-use of the block through another malloc() call. This is called using freed memory. It has the same bad consequences as referencing uninitialized data — core dumps, wrong results, mysterious crashes.
Common causes of memory leaks are unusual paths through the code. For instance, a function may allocate a block of memory, do some calculation, and then free the block again. Now a change in the requirements for the function may add a test to the calculation that detects an error condition and can return prematurely from the function. It’s easy to forget to free the allocated memory block when taking this premature exit, especially when it is added later to the code. Such leaks, once introduced, often go undetected for a long time: the error exit is taken only in a small fraction of all calls, and most modern machines have plenty of virtual memory, so the leak only becomes apparent in a long-running process that uses the leaking function frequently. Therefore, it’s important to prevent leaks from happening by having a coding convention or strategy that minimizes this kind of errors.
Since Python makes heavy use of malloc() and free() , it needs a strategy to avoid memory leaks as well as the use of freed memory. The chosen method is called reference counting. The principle is simple: every object contains a counter, which is incremented when a reference to the object is stored somewhere, and which is decremented when a reference to it is deleted. When the counter reaches zero, the last reference to the object has been deleted and the object is freed.
An alternative strategy is called automatic garbage collection. (Sometimes, reference counting is also referred to as a garbage collection strategy, hence my use of “automatic” to distinguish the two.) The big advantage of automatic garbage collection is that the user doesn’t need to call free() explicitly. (Another claimed advantage is an improvement in speed or memory usage — this is no hard fact however.) The disadvantage is that for C, there is no truly portable automatic garbage collector, while reference counting can be implemented portably (as long as the functions malloc() and free() are available — which the C Standard guarantees). Maybe some day a sufficiently portable automatic garbage collector will be available for C. Until then, we’ll have to live with reference counts.
While Python uses the traditional reference counting implementation, it also offers a cycle detector that works to detect reference cycles. This allows applications to not worry about creating direct or indirect circular references; these are the weakness of garbage collection implemented using only reference counting. Reference cycles consist of objects which contain (possibly indirect) references to themselves, so that each object in the cycle has a reference count which is non-zero. Typical reference counting implementations are not able to reclaim the memory belonging to any objects in a reference cycle, or referenced from the objects in the cycle, even though there are no further references to the cycle itself.
The cycle detector is able to detect garbage cycles and can reclaim them. The gc module exposes a way to run the detector (the collect() function), as well as configuration interfaces and the ability to disable the detector at runtime.
1.10.1. Reference Counting in Python¶
There are two macros, Py_INCREF(x) and Py_DECREF(x) , which handle the incrementing and decrementing of the reference count. Py_DECREF() also frees the object when the count reaches zero. For flexibility, it doesn’t call free() directly — rather, it makes a call through a function pointer in the object’s type object. For this purpose (and others), every object also contains a pointer to its type object.
The big question now remains: when to use Py_INCREF(x) and Py_DECREF(x) ? Let’s first introduce some terms. Nobody “owns” an object; however, you can own a reference to an object. An object’s reference count is now defined as the number of owned references to it. The owner of a reference is responsible for calling Py_DECREF() when the reference is no longer needed. Ownership of a reference can be transferred. There are three ways to dispose of an owned reference: pass it on, store it, or call Py_DECREF() . Forgetting to dispose of an owned reference creates a memory leak.
It is also possible to borrow 2 a reference to an object. The borrower of a reference should not call Py_DECREF() . The borrower must not hold on to the object longer than the owner from which it was borrowed. Using a borrowed reference after the owner has disposed of it risks using freed memory and should be avoided completely 3.
The advantage of borrowing over owning a reference is that you don’t need to take care of disposing of the reference on all possible paths through the code — in other words, with a borrowed reference you don’t run the risk of leaking when a premature exit is taken. The disadvantage of borrowing over owning is that there are some subtle situations where in seemingly correct code a borrowed reference can be used after the owner from which it was borrowed has in fact disposed of it.
A borrowed reference can be changed into an owned reference by calling Py_INCREF() . This does not affect the status of the owner from which the reference was borrowed — it creates a new owned reference, and gives full owner responsibilities (the new owner must dispose of the reference properly, as well as the previous owner).
1.10.2. Ownership Rules¶
Whenever an object reference is passed into or out of a function, it is part of the function’s interface specification whether ownership is transferred with the reference or not.
Most functions that return a reference to an object pass on ownership with the reference. In particular, all functions whose function it is to create a new object, such as PyLong_FromLong() and Py_BuildValue() , pass ownership to the receiver. Even if the object is not actually new, you still receive ownership of a new reference to that object. For instance, PyLong_FromLong() maintains a cache of popular values and can return a reference to a cached item.
Many functions that extract objects from other objects also transfer ownership with the reference, for instance PyObject_GetAttrString() . The picture is less clear, here, however, since a few common routines are exceptions: PyTuple_GetItem() , PyList_GetItem() , PyDict_GetItem() , and PyDict_GetItemString() all return references that you borrow from the tuple, list or dictionary.
The function PyImport_AddModule() also returns a borrowed reference, even though it may actually create the object it returns: this is possible because an owned reference to the object is stored in sys.modules .
When you pass an object reference into another function, in general, the function borrows the reference from you — if it needs to store it, it will use Py_INCREF() to become an independent owner. There are exactly two important exceptions to this rule: PyTuple_SetItem() and PyList_SetItem() . These functions take over ownership of the item passed to them — even if they fail! (Note that PyDict_SetItem() and friends don’t take over ownership — they are “normal.”)
When a C function is called from Python, it borrows references to its arguments from the caller. The caller owns a reference to the object, so the borrowed reference’s lifetime is guaranteed until the function returns. Only when such a borrowed reference must be stored or passed on, it must be turned into an owned reference by calling Py_INCREF() .
The object reference returned from a C function that is called from Python must be an owned reference — ownership is transferred from the function to its caller.
1.10.3. Thin Ice¶
There are a few situations where seemingly harmless use of a borrowed reference can lead to problems. These all have to do with implicit invocations of the interpreter, which can cause the owner of a reference to dispose of it.
The first and most important case to know about is using Py_DECREF() on an unrelated object while borrowing a reference to a list item. For instance:
This function first borrows a reference to list[0] , then replaces list[1] with the value 0 , and finally prints the borrowed reference. Looks harmless, right? But it’s not!
Let’s follow the control flow into PyList_SetItem() . The list owns references to all its items, so when item 1 is replaced, it has to dispose of the original item 1. Now let’s suppose the original item 1 was an instance of a user-defined class, and let’s further suppose that the class defined a __del__() method. If this class instance has a reference count of 1, disposing of it will call its __del__() method.
Since it is written in Python, the __del__() method can execute arbitrary Python code. Could it perhaps do something to invalidate the reference to item in bug() ? You bet! Assuming that the list passed into bug() is accessible to the __del__() method, it could execute a statement to the effect of del list[0] , and assuming this was the last reference to that object, it would free the memory associated with it, thereby invalidating item .
The solution, once you know the source of the problem, is easy: temporarily increment the reference count. The correct version of the function reads:
This is a true story. An older version of Python contained variants of this bug and someone spent a considerable amount of time in a C debugger to figure out why his __del__() methods would fail…
The second case of problems with a borrowed reference is a variant involving threads. Normally, multiple threads in the Python interpreter can’t get in each other’s way, because there is a global lock protecting Python’s entire object space. However, it is possible to temporarily release this lock using the macro Py_BEGIN_ALLOW_THREADS , and to re-acquire it using Py_END_ALLOW_THREADS . This is common around blocking I/O calls, to let other threads use the processor while waiting for the I/O to complete. Obviously, the following function has the same problem as the previous one:
1.10.4. NULL Pointers¶
In general, functions that take object references as arguments do not expect you to pass them NULL pointers, and will dump core (or cause later core dumps) if you do so. Functions that return object references generally return NULL only to indicate that an exception occurred. The reason for not testing for NULL arguments is that functions often pass the objects they receive on to other function — if each function were to test for NULL , there would be a lot of redundant tests and the code would run more slowly.
It is better to test for NULL only at the “source:” when a pointer that may be NULL is received, for example, from malloc() or from a function that may raise an exception.
The macros Py_INCREF() and Py_DECREF() do not check for NULL pointers — however, their variants Py_XINCREF() and Py_XDECREF() do.
The macros for checking for a particular object type ( Pytype_Check() ) don’t check for NULL pointers — again, there is much code that calls several of these in a row to test an object against various different expected types, and this would generate redundant tests. There are no variants with NULL checking.
The C function calling mechanism guarantees that the argument list passed to C functions ( args in the examples) is never NULL — in fact it guarantees that it is always a tuple 4.
It is a severe error to ever let a NULL pointer “escape” to the Python user.
1.11. Writing Extensions in C++¶
It is possible to write extension modules in C++. Some restrictions apply. If the main program (the Python interpreter) is compiled and linked by the C compiler, global or static objects with constructors cannot be used. This is not a problem if the main program is linked by the C++ compiler. Functions that will be called by the Python interpreter (in particular, module initialization functions) have to be declared using extern "C" . It is unnecessary to enclose the Python header files in extern "C" <. >— they use this form already if the symbol __cplusplus is defined (all recent C++ compilers define this symbol).
1.12. Providing a C API for an Extension Module¶
Many extension modules just provide new functions and types to be used from Python, but sometimes the code in an extension module can be useful for other extension modules. For example, an extension module could implement a type “collection” which works like lists without order. Just like the standard Python list type has a C API which permits extension modules to create and manipulate lists, this new collection type should have a set of C functions for direct manipulation from other extension modules.
At first sight this seems easy: just write the functions (without declaring them static , of course), provide an appropriate header file, and document the C API. And in fact this would work if all extension modules were always linked statically with the Python interpreter. When modules are used as shared libraries, however, the symbols defined in one module may not be visible to another module. The details of visibility depend on the operating system; some systems use one global namespace for the Python interpreter and all extension modules (Windows, for example), whereas others require an explicit list of imported symbols at module link time (AIX is one example), or offer a choice of different strategies (most Unices). And even if symbols are globally visible, the module whose functions one wishes to call might not have been loaded yet!
Portability therefore requires not to make any assumptions about symbol visibility. This means that all symbols in extension modules should be declared static , except for the module’s initialization function, in order to avoid name clashes with other extension modules (as discussed in section The Module’s Method Table and Initialization Function ). And it means that symbols that should be accessible from other extension modules must be exported in a different way.
Python provides a special mechanism to pass C-level information (pointers) from one extension module to another one: Capsules. A Capsule is a Python data type which stores a pointer ( void * ). Capsules can only be created and accessed via their C API, but they can be passed around like any other Python object. In particular, they can be assigned to a name in an extension module’s namespace. Other extension modules can then import this module, retrieve the value of this name, and then retrieve the pointer from the Capsule.
There are many ways in which Capsules can be used to export the C API of an extension module. Each function could get its own Capsule, or all C API pointers could be stored in an array whose address is published in a Capsule. And the various tasks of storing and retrieving the pointers can be distributed in different ways between the module providing the code and the client modules.
Whichever method you choose, it’s important to name your Capsules properly. The function PyCapsule_New() takes a name parameter ( const char * ); you’re permitted to pass in a NULL name, but we strongly encourage you to specify a name. Properly named Capsules provide a degree of runtime type-safety; there is no feasible way to tell one unnamed Capsule from another.
In particular, Capsules used to expose C APIs should be given a name following this convention:
The convenience function PyCapsule_Import() makes it easy to load a C API provided via a Capsule, but only if the Capsule’s name matches this convention. This behavior gives C API users a high degree of certainty that the Capsule they load contains the correct C API.
The following example demonstrates an approach that puts most of the burden on the writer of the exporting module, which is appropriate for commonly used library modules. It stores all C API pointers (just one in the example!) in an array of void pointers which becomes the value of a Capsule. The header file corresponding to the module provides a macro that takes care of importing the module and retrieving its C API pointers; client modules only have to call this macro before accessing the C API.
The exporting module is a modification of the spam module from section A Simple Example . The function spam.system() does not call the C library function system() directly, but a function PySpam_System() , which would of course do something more complicated in reality (such as adding “spam” to every command). This function PySpam_System() is also exported to other extension modules.
The function PySpam_System() is a plain C function, declared static like everything else: