Spec-Zone.ru › NumPy 2.0

numpy.distutils руководство пользователя

Предупреждение

numpy.distutils устарел и будет удален для Python >= 3.12. Для получения более подробной информации см. Статус 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 python3
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. Эта возможность может быть использована для поддержания очень похожих блоков кода, требующих только простых изменений между блоками. Во время фазы сборки настройки, если встречается файл-шаблон с именем <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 /* TIMEDELTA to non-float types */
 2
 3 /**begin repeat
 4  *
 5  * #TOTYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG,
 6  *           LONGLONG, ULONGLONG, DATETIME,
 7  *           TIMEDELTA#
 8  * #totype = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
 9  *           npy_long, npy_ulong, npy_longlong, npy_ulonglong,
10  *           npy_datetime, npy_timedelta#
11  */
12
13 /**begin repeat1
14  *
15  * #FROMTYPE = TIMEDELTA#
16  * #fromtype = npy_timedelta#
17  */
18 static void
19 @FROMTYPE@_to_@TOTYPE@(void *input, void *output, npy_intp n,
20         void *NPY_UNUSED(aip), void *NPY_UNUSED(aop))
21 {
22     const @fromtype@ *ip = input;
23     @totype@ *op = output;
24
25     while (n--) {
26         *op++ = (@totype@)*ip++;
27     }
28 }
29 /**end repeat1**/
30
31 /**end repeat**/

Предварительная обработка файлов исходного кода 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) — возвращает путь к модулю относительно 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.
"""

# 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 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–2024 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/2.0/reference/distutils_guide.html

Spec-Zone.ru

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