NumPy Distutils — Руководство пользователя
Структура SciPy
В настоящее время проект SciPy состоит из двух пакетов:
- NumPy — он предоставляет пакеты, такие как:
- numpy.distutils — расширение Python distutils
- numpy.f2py — инструмент для связывания Fortran/C кода с Python
- numpy.core — будущий заменитель пакетов Numeric и numarray
- numpy.lib — дополнительные служебные функции
- numpy.testing — инструменты NumPy-стиля для тестирования на единицу
- и т.д.
- SciPy — коллекция научных инструментов для Python.
Целью этого документа является описание того, как добавить новые инструменты в SciPy.
Требования к пакетам SciPy
SciPy состоит из пакетов Python, называемых пакетами SciPy, которые доступны пользователям Python через пространство имён scipy. Каждый пакет SciPy может содержать другие пакеты SciPy. И так далее. Поэтому дерево каталогов SciPy является деревом пакетов с произвольной глубиной и шириной. Любой пакет SciPy может зависеть от пакетов NumPy, но зависимость от других пакетов SciPy следует сохранять минимальной или нулевой.
Пакет SciPy содержит, помимо своих исходных кодов, следующие файлы и каталоги:
-
setup.py— скрипт сборки -
__init__.py— инициализатор пакета -
tests/— каталог модулей тестирования
Их содержимое описано ниже.
Файл setup.py
Для добавления пакета Python в SciPy, его скрипт сборки (setup.py) должен удовлетворять определенным требованиям. Наиболее важное требование заключается в том, что пакет должен определить функцию configuration(parent_package='',top_path=None), которая возвращает словарь, подходящий для передачи функции numpy.distutils.core.setup(..). Для упрощения построения этого словаря, numpy.distutils.misc_util предоставляет класс Configuration, описанный ниже.
Пример пакета SciPy на чистом Python
Ниже приведён пример минимального файла setup.py для чистого пакета SciPy:
#!/usr/bin/env python
def configuration(parent_package='',top_path=None):
from numpy.distutils.misc_util import Configuration
config = Configuration('mypackage',parent_package,top_path)
return config
if __name__ == "__main__":
from numpy.distutils.core import setup
#setup(**configuration(top_path='').todict())
setup(configuration=configuration)
Аргументы функции configuration задают имя родительского пакета SciPy (parent_package) и расположение каталога основного скрипта setup.py (top_path). Эти аргументы, наряду с именем текущего пакета, должны быть переданы конструктору Configuration.
Конструктор Configuration имеет четвёртый необязательный аргумент, package_path, который может использоваться, когда файлы пакета находятся в другом месте, отличном от каталога файла setup.py.
Остальные аргументы Configuration — это все именованные аргументы, которые будут использоваться для инициализации атрибутов экземпляра Configuration. Обычно эти ключевые слова совпадают с теми, которые ожидает функция setup(..), например, packages, ext_modules, data_files, include_dirs, libraries, headers, scripts, package_dir, и т. д. Однако прямое указание этих ключевых слов не рекомендуется, так как содержимое этих ключевых аргументов не будет обрабатываться или проверяться на соответствие системе сборки SciPy.
Наконец, Configuration имеет метод .todict(), который возвращает все данные конфигурации в виде словаря, подходящего для передачи функции setup(..).
Атрибуты экземпляра Configuration
В дополнение к атрибутам, которые можно указать с помощью именованных аргументов конструктора Configuration, экземпляр Configuration (обозначим его как config) имеет следующие атрибуты, которые могут быть полезны при написании скриптов сборки:
-
config.name— полное имя текущего пакета. Имена родительских пакетов можно получить какconfig.name.split('.'). -
config.local_path— путь к расположению текущего файлаsetup.py. -
config.top_path— путь к расположению основного файлаsetup.py.
Методы экземпляра Configuration
-
config.todict()— возвращает словарь конфигурации, подходящий для передачи функцииnumpy.distutils.core.setup(..). -
config.paths(*paths) --- applies ``glob.glob(..)— обрабатывает элементыpaths, если необходимо. Исправляет элементpaths, который является относительным кconfig.local_path. -
config.get_subpackage(subpackage_name,subpackage_path=None)— возвращает список конфигураций подпакетов. Подпакет ищется в текущем каталоге под именемsubpackage_name, но путь также можно указать через необязательный аргументsubpackage_path. Еслиsubpackage_nameуказан какNone, то имя подпакета будет взято как имя файлаsubpackage_path. Любые*, используемые для имён подпакетов, расширяются как шаблоны. -
config.add_subpackage(subpackage_name,subpackage_path=None)— добавляет конфигурацию подпакета SciPy в текущую. Значение и использование аргументов объяснено выше, см. методconfig.get_subpackage(). -
config.add_data_files(*files)— добавляетfilesв списокdata_files. Если элементfilesявляется кортежем, то его первый элемент определяет суффикс, где данные файлы копируются относительно каталога установки пакета, а второй элемент указывает путь к файлам данных. По умолчанию файлы данных копируются в каталог установки пакета. Например,config.add_data_files('foo.dat', ('fun',['gun.dat','nun/pun.dat','/tmp/sun.dat']), 'bar/car.dat'. '/full/path/to/can.dat', )установит файлы данных по следующим путям
<installation path of config.name package>/ foo.dat fun/ gun.dat pun.dat sun.dat bar/ car.dat can.datПуть к файлам данных может быть функцией, не принимающей аргументов и возвращающей путь(и) к файлам данных — это полезно, когда файлы данных генерируются во время сборки пакета. (XXX: объяснить шаг, когда эта функция вызывается точно)
-
config.add_data_dir(data_path)— добавляет каталогdata_pathрекурсивно вdata_files. Вся древовидная структура каталогов, начинающаяся сdata_path, будет скопирована в каталог установки пакета. Еслиdata_pathявляется кортежем, то его первый элемент определяет суффикс, куда копируются файлы данных относительно каталога установки пакета, а второй элемент указывает путь к каталогу данных. По умолчанию каталоги данных копируются в каталог установки пакета под именемdata_path. Например,config.add_data_dir('fun') # fun/ contains foo.dat bar/car.dat config.add_data_dir(('sun','fun')) config.add_data_dir(('gun','/full/path/to/fun'))установит файлы данных по следующим путям
<installation path of config.name package>/ fun/ foo.dat bar/ car.dat sun/ foo.dat bar/ car.dat gun/ foo.dat bar/ car.dat -
config.add_include_dirs(*paths)— добавляетpathsв списокinclude_dirs. Этот список будет виден всем модулям расширения текущего пакета. -
config.add_headers(*files)— добавляетfilesв списокheaders. По умолчанию заголовки будут установлены в каталоге<prefix>/include/pythonX.X/<config.name.replace('.','/')>/. Если элементfilesявляется кортежем, то его первый аргумент определяет суффикс установки относительно пути<prefix>/include/pythonX.X/. Это метод Python distutils; его использование не рекомендуется для NumPy и SciPy в пользуconfig.add_data_files(*files). -
config.add_scripts(*files)— добавляетfilesв списокscripts. Скрипты будут установлены в каталоге<prefix>/bin/. -
config.add_extension(name,sources,**kw)— создаёт и добавляет экземплярExtensionв списокext_modules. Первый аргументnameопределяет имя модуля расширения, которое будет установлено в пакетеconfig.name. Второй аргумент — список исходных кодов. Методadd_extensionтакже принимает именованные аргументы, которые передаются конструкторуExtension. Список разрешённых ключевых слов следующий:include_dirs,define_macros,undef_macros,library_dirs,libraries,runtime_library_dirs,extra_objects,extra_compile_args,extra_link_args,export_symbols,swig_opts,depends,language,f2py_options,module_dirs,extra_info,extra_f77_compile_args,extra_f90_compile_args.Обратите внимание, что метод
config.pathsприменяется ко всем спискам, которые могут содержать пути.extra_info— это словарь или список словарей, содержимое которых будет добавлено к ключевым аргументам. Списокdependsсодержит пути к файлам или каталогам, от которых зависят исходные коды модуля расширения. Если какой-либо путь в спискеdependsновее, чем модуль расширения, то модуль будет перестроен.Список исходных кодов может содержать функции («генераторы исходных кодов») с шаблоном
def <funcname>(ext, build_dir): return <source(s) or None>. ЕслиfuncnameвозвращаетNone, исходные коды не генерируются. А если у экземпляраExtensionнет исходных кодов после обработки всех генераторов исходных кодов, модуль расширения не будет создан. Это рекомендуемый способ условного определения модулей расширения. Функции генераторов исходных кодов вызываются командойbuild_srcкомандыnumpy.distutils.Например, вот типичная функция генератора исходных кодов:
def generate_source(ext,build_dir): import os from distutils.dep_util import newer target = os.path.join(build_dir,'somesource.c') if newer(target,__file__): # create target file return targetПервый аргумент содержит экземпляр Extension, который может быть полезен для доступа к его атрибутам, таким как списки
depends,sources, и т. д., и их модификации в процессе сборки. Второй аргумент предоставляет путь к каталогу сборки, который необходимо использовать при создании файлов на диске. -
config.add_library(name, sources, **build_info)— добавляет библиотеку в списокlibraries. Разрешённые ключевые аргументы:depends,macros,include_dirs,extra_compiler_args,f2py_options,extra_f77_compile_args,extra_f90_compile_args. Смотрите метод.add_extension()для получения дополнительной информации об аргументах. -
config.have_f77c()— возвращает True, если компилятор Fortran 77 доступен (читай: простой код Fortran 77 скомпилирован успешно). -
config.have_f90c()— возвращает True, если компилятор Fortran 90 доступен (читай: простой код Fortran 90 скомпилирован успешно). -
config.get_version()— возвращает строку версии текущего пакета,Noneесли информация о версии не могла быть обнаружена. Этот метод сканирует файлы__version__.py,<packagename>_version.py,version.py,__svn_version__.pyв поисках строковых переменныхversion,__version__,<packagename>_version. -
config.make_svn_version_py()— добавляет функцию данных в списокdata_files, которая сгенерирует файл__svn_version__.pyв каталог текущего пакета. Файл будет удалён из каталога исходных кодов при завершении работы Python. -
config.get_build_temp_dir()— возвращает путь к временному каталогу. Это место, где следует создавать временные файлы. -
config.get_distribution()— возвращает экземплярDistributiondistutils. -
config.get_config_cmd()— возвращает экземпляр команды конфигурацииnumpy.distutils. -
config.get_info(*names)—
Файлы шаблонов
XXX: Опишите, как файлы с расширениями .f.src, .pyf.src, .c.src, и т. д. предварительно обрабатываются командой build_src.
Полезные функции в numpy.distutils.misc_util
-
get_numpy_include_dirs()— возвращает список базовых каталогов заголовочных файлов NumPy. Базовые каталоги заголовочных файлов NumPy содержат заголовочные файлы, такие какnumpy/arrayobject.h,numpy/funcobject.hи т. д. Для установленного NumPy возвращаемый список имеет длину 1, но при построении NumPy список может содержать больше каталогов, например, путь к файлуconfig.h, который файлnumpy/base/setup.pyгенерирует и используется заголовочными файламиnumpy. -
append_path(prefix,path)— умное добавлениеpathкprefix. -
gpaths(paths, local_path='')— применение glob к путям и добавлениеlocal_path, если необходимо. -
njoin(*path)— соединение компонентов пути + преобразование пути, разделенного/, в путь, разделенныйos.sep, и разрешение..,.в путях. Пример:njoin('a',['b','./c'],'..','g') -> os.path.join('a','b','g'). -
minrelpath(path)— разрешает точки вpath. -
rel_path(path, parent_path)— возвращаетpathотносительноparent_path. -
def get_cmd(cmdname,_cache={})— возвращает экземпляр командыnumpy.distutils. all_strings(lst)has_f_sources(sources)has_cxx_sources(sources)-
filter_sources(sources)— возвращаетc_sources, cxx_sources, f_sources, fmodule_sources get_dependencies(sources)is_local_src_dir(directory)get_ext_source_files(ext)get_script_files(scripts)get_lib_source_files(lib)get_data_files(data)-
dot_join(*args)— объединяет ненулевые аргументы точкой. -
get_frame(level=0)— возвращает объект фрейма из стека вызовов с заданным уровнем. cyg2win32(path)-
mingw32()— возвращаетTrueпри использовании среды mingw32. -
terminal_has_colors(),red_text(s),green_text(s),yellow_text(s),blue_text(s),cyan_text(s) -
get_path(mod_name,parent_path=None)— возвращает путь к модулю относительно parent_path, если задан. Обрабатывает также модули__main__и__builtin__. -
allpath(name)— заменяет/наos.sepвname. -
cxx_ext_match,fortran_ext_match,f90_ext_match,f90_module_name_match
numpy.distutils.system_info модуль
get_info(name,notfound_action=0)combine_paths(*args,**kws)show_all()
numpy.distutils.cpuinfo модуль
cpuinfo
numpy.distutils.log модуль
set_verbosity(v)
numpy.distutils.exec_command модуль
get_pythonexe()find_executable(exe, path=None)exec_command( command, execute_in='', use_shell=None, use_tee=None, **env )
Файл __init__.py
Заголовок типичного SciPy __init__.py:
"""
Package docstring, typically with a brief description and function listing.
"""
# py3k related imports
from __future__ import division, print_function, absolute_import
# import functions into module namespace
from .subpackage import *
...
__all__ = [s for s in dir() if not s.startswith('_')]
from numpy.testing import Tester
test = Tester().test
bench = Tester().bench
Обратите внимание, что подмодули NumPy по-прежнему используют файл с именем info.py, в котором определены строка документации модуля и словарь __all__. Эти файлы будут удалены в какой-то момент.
Дополнительные возможности в NumPy Distutils
Указание параметров config_fc для библиотек в скрипте setup.py
Можно указать параметры config_fc в скриптах setup.py. Например, использование
- config.add_library(‘library’,
- sources=[…], config_fc={‘noopt’:(__file__,1)})
скомпилирует library исходные файлы без флагов оптимизации.
Рекомендуется указывать только те параметры config_fc, которые не зависят от компилятора.
Получение дополнительных параметров компилятора Fortran 77 из исходного кода
Некоторые старые коды Fortran требуют специальных параметров компилятора для корректной работы. Для указания параметров компилятора для каждого исходного файла numpy.distutils компилятор Fortran ищет следующую структуру:
CF77FLAGS(<fcompiler type>) = <fcompiler f77flags>
в первых 20 строках исходного кода и использует f77flags для указанного типа компилятора (первый символ C является необязательным).
TODO: Эта функция может быть легко расширена и для кодов Fortran 90. Дайте нам знать, если вам понадобится такая возможность.
© 2005–2019 NumPy Developers
Licensed under the 3-clause BSD License.
https://docs.scipy.org/doc/numpy-1.16.1/reference/distutils_guide.html