Spec-Zone.ru › NumPy 1.17

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() — возвращает экземпляр Distribution distutils.
  • config.get_config_cmd() — возвращает экземпляр команды конфигурации numpy.distutils.
  • config.get_info(*names) —

Преобразование файлов .src с использованием шаблонов

NumPy distutils поддерживает автоматическое преобразование исходных файлов с именем <somefile>.src. Эта возможность может использоваться для поддержания очень похожих блоков кода, требующих только простых изменений между блоками. Во время этапа сборки setup, если обнаружен файл-шаблон с именем <somefile>.src, новый файл с именем <somefile> создается из шаблона и помещается в директорию сборки для использования вместо него. Поддерживаются два вида преобразования шаблонов. Первый вид происходит для файлов с именем <file>.ext.src, где ext — это распознаваемое расширение Fortran (f, f90, f95, f77, for, ftn, pyf). Второй вид используется для всех других случаев.

Файлы Fortran

Этот преобразователь шаблонов будет дублировать все блоки функций и подпрограмм в файле с именами, содержащими ‘<…>’, в соответствии с правилами в ‘<…>’. Количество слов, разделённых запятыми в ‘<…>’, определяет количество повторений блока. То, какими словами являются эти слова, указывает, на что должно быть заменено это правило повторения, ‘<…>’, в каждом блоке. Все правила повторения в блоке должны содержать одинаковое количество слов, разделённых запятыми, указывающих на количество повторений этого блока. Если слово в правиле повторения требует запятой, стрелки влево или вправо, то добавьте перед ним обратный слэш «\». Если слово в правиле повторения совпадает с ‘ \ <индекс>’, то оно будет заменено на <индекс>-е слово в том же правиле повторения. Существуют два вида правил повторения: именованное и короткое.

Именованное правило повторения

Именованное правило повторения полезно, когда тот же набор повторений должен быть использован несколько раз в блоке. Оно задаётся с помощью <rule1=item1, item2, item3,…, itemN>, где N — количество повторений блока. При каждом повторении блока всё выражение ‘<…>’ будет заменено сначала на item1, затем на item2 и так далее, пока не будут выполнены N повторений. После того, как именованное правило повторения было введено, то же правило повторения может быть использовано в текущем блоке, ссылаясь только на имя (т.е. <rule1>).

Короткое правило повторения

Короткое правило повторения выглядит как <item1, item2, item3, …, itemN>. Правило указывает, что всё выражение ‘<…>’ должно быть заменено сначала на item1, затем на item2 и так далее, пока не будут выполнены N повторений.

Предопределённые имена

Доступны следующие предопределённые именованные правила повторения:

  • <prefix=s,d,c,z>
  • <_c=s,d,c,z>
  • <_t=real, double precision, complex, double complex>
  • <ftype=real, double precision, complex, double complex>
  • <ctype=float, double, complex_float, complex_double>
  • <ftypereal=float, double precision, \0, \1>
  • <ctypereal=float, double, \0, \1>

Другие файлы

Файлы, не являющиеся файлами Fortran, используют отдельный синтаксис для определения блоков шаблонов, которые должны быть повторены с использованием расширения переменных, аналогичного именованным правилам повторения для специфичных для Fortran повторений.

NumPy Distutils предварительно обрабатывает исходные файлы C (расширение: .c.src) на языке пользовательского шаблонирования для генерации кода C. Символ @ используется для обертывания переменных в стиле макросов, чтобы обеспечить механизм подстановки строк, который может описывать (например) набор типов данных.

Блоки языка шаблонов ограничены строками /**begin repeat и /**end repeat**/, которые также могут быть вложены с использованием последовательных номеров разделителей, таких как /**begin repeat1 и /**end repeat1**/.

1. «/**begin repeat “ на отдельной строке отмечает начало фрагмента, который должен быть повторён.

2. Расширения именованных переменных определяются с помощью #name=item1, item2, item3, ..., itemN# и размещаются на последующих строках. Эти переменные заменяются в каждом блоке повторения соответствующим словом. Все именованные переменные в одном и том же блоке повторения должны определять одинаковое количество слов.

3. При указании правила повторения для именованной переменной item*N является сокращением для item, item, ..., item повторяемого N раз. Кроме того, круглые скобки в сочетании с *N могут использоваться для группирования нескольких элементов, которые должны быть повторены. Таким образом, #name=(item1, item2)*4# эквивалентно #name=item1, item2, item1, item2, item1, item2, item1, item2#

4. «*/ “ на отдельной строке отмечает конец именования расширения переменных. Следующая строка — это первая строка, которая будет повторена с использованием именованных правил.

5. Внутри блока, который должен быть повторён, переменные, которые должны быть расширены, указаны как @name@

6. «/**end repeat**/ “ на отдельной строке отмечает предыдущую строку как последнюю строку блока, который должен быть повторён.

7. В цикле в исходном коде NumPy C может быть переменная @TYPE@, предназначенная для подстановки строк, которая предварительно обрабатывается до нескольких в остальном одинаковых циклов с несколькими строками, такими как INT, LONG, UINT, ULONG. Синтаксис в стиле @TYPE@ таким образом уменьшает дублирование кода и нагрузку по его обслуживанию, имитируя языки, которые имеют поддержку универсальных типов.

Правила выше могут быть более понятны на следующем примере исходного кода шаблона:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

Предварительная обработка файлов исходного кода C с универсальными типами (как в собственном NumPy, так и в любом стороннем пакете, использующем NumPy Distutils), выполняется с помощью conv_template.py. Файлы C, специфичные для типов, сгенерированные (расширение: .c) этими модулями в процессе сборки, готовы к компиляции. Этот вид универсального типирования также поддерживается для файлов заголовков C (предварительно обработанных для создания файлов .h).

Полезные функции в 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) — возвращает путь к модулю относительно родительского пути, если он указан. Обрабатывает также модули __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 требуют специальных параметров компилятора для корректной работы. Для указания параметров компилятора для каждого исходного файла, компилятор Fortran numpy.distutils ищет следующий шаблон:

CF77FLAGS(<fcompiler type>) = <fcompiler f77flags>

в первых 20 строках исходного кода и использует f77flags для указанного типа fcompiler (первый символ C является необязательным).

TODO: Эта функция может быть легко расширена и для кодов Fortran 90. Сообщите нам, если вам понадобится такая функция.

© 2005–2019 NumPy Developers
Licensed under the 3-clause BSD License.
https://docs.scipy.org/doc/numpy-1.17.0/reference/distutils_guide.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API