Entry points specification¶
Entry points are a mechanism for an installed distribution to advertise components it provides to be discovered and used by other code. For example:
- Distributions can specify console_scripts entry points, each referring to a function. When pip (or another console_scripts aware installer) installs the distribution, it will create a command-line wrapper for each entry point.
- Applications can use entry points to load plugins; e.g. Pygments (a syntax highlighting tool) can use additional lexers and styles from separately installed packages. For more about this, see Creating and discovering plugins .
The entry point file format was originally developed to allow packages built with setuptools to provide integration point metadata that would be read at runtime with importlib.metadata . It is now defined as a PyPA interoperability specification in order to allow build tools other than setuptools to publish importlib.metadata compatible entry point metadata, and runtime libraries other than importlib.metadata to portably read published entry point metadata (potentially with different caching and conflict resolution strategies).
Data model¶
Conceptually, an entry point is defined by three required properties:
- The group that an entry point belongs to indicates what sort of object it provides. For instance, the group console_scripts is for entry points referring to functions which can be used as a command, while pygments.styles is the group for classes defining pygments styles. The consumer typically defines the expected interface. To avoid clashes, consumers defining a new group should use names starting with a PyPI name owned by the consumer project, followed by . . Group names must be one or more groups of letters, numbers and underscores, separated by dots (regex ^\w+(\.\w+)*$ ).
- The name identifies this entry point within its group. The precise meaning of this is up to the consumer. For console scripts, the name of the entry point is the command that will be used to launch it. Within a distribution, entry point names should be unique. If different distributions provide the same name, the consumer decides how to handle such conflicts. The name may contain any characters except = , but it cannot start or end with any whitespace character, or start with [ . For new entry points, it is recommended to use only letters, numbers, underscores, dots and dashes (regex [\w.-]+ ).
- The object reference points to a Python object. It is either in the form importable.module , or importable.module:object.attr . Each of the parts delimited by dots and the colon is a valid Python identifier. It is intended to be looked up like this:
import importlib modname, qualname_separator, qualname = object_ref.partition(':') obj = importlib.import_module(modname) if qualname_separator: for attr in qualname.split('.'): obj = getattr(obj, attr)
Some tools call this kind of object reference by itself an ‘entry point’, for want of a better term, especially where it points to a function to launch a program.
There is also an optional property: the extras are a set of strings identifying optional features of the distribution providing the entry point. If these are specified, the entry point requires the dependencies of those ‘extras’. See the metadata field Provides-Extra (multiple use) .
Using extras for an entry point is no longer recommended. Consumers should support parsing them from existing distributions, but may then ignore them. New publishing tools need not support specifying extras. The functionality of handling extras was tied to setuptools’ model of managing ‘egg’ packages, but newer tools such as pip and virtualenv use a different model.
File format¶
Entry points are defined in a file called entry_points.txt in the *.dist-info directory of the distribution. This is the directory described in Recording installed projects for installed distributions, and in Binary distribution format for wheels. The file uses the UTF-8 character encoding.
The file contents are in INI format, as read by Python’s configparser module. However, configparser treats names as case-insensitive by default, whereas entry point names are case sensitive. A case-sensitive config parser can be made like this:
import configparser class CaseSensitiveConfigParser(configparser.ConfigParser): optionxform = staticmethod(str)
The entry points file must always use = to delimit names from values (whereas configparser also allows using : ).
The sections of the config file represent entry point groups, the names are names, and the values encode both the object reference and the optional extras. If extras are used, they are a comma-separated list inside square brackets.
Within a value, readers must accept and ignore spaces (including multiple consecutive spaces) before or after the colon, between the object reference and the left square bracket, between the extra names and the square brackets and colons delimiting them, and after the right square bracket. The syntax for extras is formally specified as part of PEP 508 (as extras ) and restrictions on values specified in PEP 685. For tools writing the file, it is recommended only to insert a space between the object reference and the left square bracket.
[console_scripts] foo = foomod:main # One which depends on extras: foobar = foomod:main_bar [bar,baz] # pytest plugins refer to a module, so there is no ':obj' [pytest11] nbval = nbval.plugin
Use for scripts¶
Two groups of entry points have special significance in packaging: console_scripts and gui_scripts . In both groups, the name of the entry point should be usable as a command in a system shell after the package is installed. The object reference points to a function which will be called with no arguments when this command is run. The function may return an integer to be used as a process exit code, and returning None is equivalent to returning 0 .
For instance, the entry point mycmd = mymod:main would create a command mycmd launching a script like this:
import sys from mymod import main sys.exit(main())
The difference between console_scripts and gui_scripts only affects Windows systems. console_scripts are wrapped in a console executable, so they are attached to a console and can use sys.stdin , sys.stdout and sys.stderr for input and output. gui_scripts are wrapped in a GUI executable, so they can be started without a console, but cannot use standard streams unless application code redirects them. Other platforms do not have the same distinction.
Install tools are expected to set up wrappers for both console_scripts and gui_scripts in the scripts directory of the install scheme. They are not responsible for putting this directory in the PATH environment variable which defines where command-line tools are found.
As files are created from the names, and some filesystems are case-insensitive, packages should avoid using names in these groups which differ only in case. The behaviour of install tools when names differ only in case is undefined.
Table of Contents
Точка входа
В программах, написанных на Python часто можно увидеть такую конструкцию:
Это точка входа — место, с которого начинает выполняться ваша программа. Но какие еще значения может принимать переменная __name__ ? Зачем вообще нужна эта проверка?
Переменная __name__
Для начала, попробуем провести несколько экспериментов. Создадим папку с тремя файлами: my_module.py , calculations.py и processing.py . А теперь выведем на экран переменные __name__ каждого из этих файлов. В каждом случае результат будет одинаковым.
>>> __name__ '__main__' А теперь попробуем импортировать модули, и снова проверить значение их переменных `__name__`. ```pycon >>> import my_module >>> import calculations >>> my_module.__name__ my_module >>> calculations.__name__ calculations >>> .dir() [. '__name__', . 'calculations', 'my_module']
Как видите, переменная __name__ теперь содержит название файла импортированного модуля. Функция dir() в нашем случае возвращает глобальное пространство имен. В конце списка притаились те самые имена импортированных модулей. Теперь мы сможем обращаться к их содержимому через эти названия.
Точка входа
Давайте разберем работу типичной точки входа на примере файла processing.py .
import calculations import my_module def main(): while True: inp = input("Insert value:") converted = calculations.convert(inp) transformed = calculations.transform(converted) print(my_module.output(transformed)) if __name__ == "__main__": main()
Сначала интерпретатор импортирует модули, затем определяет функцию main() , и доходит до блока if __name__ == ‘__main__’: . Если пользователь непосредственно запустил файл processing.py , условие будет удовлетворено, и начнется выполнение функции main() . Пользователь сможет ввести какую-то строку в консоль, она будет обработана функциями из модулей calculations и my_module , а затем выведена на экран. Цикл будет повторяться, пока пользователь не завершит программу.
Но представьте себе, что мы решили сделать более сложную программу, которая использует те же функции. Чтобы не переписывать тот же самый код, мы импортировали processing.py . Если бы мы не проверяли значение переменной __name__ , функция main() запустилась бы при импорте. Программа застряла бы в одном бесконечном цикле while , а интерпретатор никогда не дошел бы до кода нашей новой программы.
>>> import processing Insert value:
Это было бы крайне нежелательно. Поэтому мы и проверяем содержимое переменной __name__ перед запуском функции main() . Поскольку при импорте ее содержимое меняется на название модуля — processing , то проверка не будет пройдена, и main() не запустится. Зато мы сможем использовать любые объекты импортированного модуля:
import processing mode = input('Mode:') if mode == 'standard': processing.main() else print(processing.my_module.output(input()))
Заключение
С точки входа начинается выполнение программы. Содержимое блока if __name__ == ‘__main__’: не выполняется, если файл импортирован, а не запущен напрямую. Это позволяет разместить в нем код, который помешал бы импорту содержимого модуля, но нужен при непосредственном доступе. Использование этой конструкции — хорошая практика, которая поможет избежать проблем при импорте вашего модуля.
Практический Python для начинающих
Станьте junior Python программистом за 7 месяцев
Основная функция в Python
Основная функция Python выполняется только тогда, когда она используется, как программа на Python. Как вы знаете, мы также можем импортировать программу на Python, как модуль, в этом случае основной метод не должен выполняться.
Что такое основная функция в Python?
Основная функция в Python – это точка входа в любую программу. Но интерпретатор последовательно выполняет код исходного файла и не вызывает никаких методов, если он не является частью кода. Но если это непосредственно часть кода, то она будет выполнена при импорте файла, как модуля.
Вот почему существует специальный метод определения основного метода в программе Python, чтобы он выполнялся только тогда, когда программа запускается напрямую, а не выполняется при импорте, как модуль. Давайте посмотрим, как определить основную функцию в простой программе.
print("Hello") print("__name__ value: ", __name__) def main(): print("python main function") if __name__ == '__main__': main()
- Когда программа python выполняется, интерпретатор начинает выполнять код внутри нее. Он также устанавливает несколько неявных значений переменных, одно из них __name__, значение которого установлено как __main__.
- Для основной функции мы должны определить функцию, а затем использовать условие if __name__ == ‘__main__’ для выполнения этой функции.
- Если исходный файл импортируется как модуль, интерпретатор python устанавливает значение __name__ для имени модуля, поэтому условие if вернет false и основной метод не будет выполняться.
- Python предоставляет нам гибкость, позволяющую сохранить любое имя для основного метода, однако лучше всего называть его методом main(). Код ниже вполне подходит, но не рекомендуется.
def main1(): print("python main function") if __name__ == '__main__': main1()
На изображении ниже показан результат, когда python_main_function.py выполняется как исходный файл.
Основная функция, как модуль
Теперь давайте используем указанный выше исходный файл Python в качестве модуля и импортируем его в другую программу python_import.py.
import python_main_function print("Done")
Теперь, когда выполняется вышеуказанная программа, производится вывод ниже.
Hello __name__ value: python_main_function Done
Обратите внимание, что первые две строки печатаются из исходного файла python_main_function.py. Обратите внимание, что значение __name__ отличается, и, следовательно, основной метод не выполняется.
Операторы программы python выполняются построчно, поэтому важно определить метод main() сначала перед условием if для выполнения основного метода. В противном случае вы получите ошибку, так как NameError: имя ‘main’ не определено.