Spec-Zone.ru › NumPy 1.18

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

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

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

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

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

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

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

© 2005–2020 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/1.18/reference/distutils_guide.html

Spec-Zone.ru

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