Получить значение __version__ из файла, не используя imp.load_source?
Ранее я сделал следующее, чтобы получить строку версии:
>>> filepath = './somemodule/__init__.py'
>>> name = 'dummy'
>>> module_source = imp.load_source(name, filepath)
>>> module_source.__version__
1.0.0
Теперь, когда imp
устарел в Python 3 (я на 3.7.1), что было бы хорошей заменой load_source
которая просто потребует библиотеки std?
Это кажется мне немного запутанным И load_module
фактически устарела:
>>> from importlib.machinery import SourceFileLoader
>>> loaded = SourceFileLoader(name, filepath).load_module()
>>> loaded.__version__
1.0.0
РЕДАКТИРОВАНИЕ № 1:
Это обсуждается в разделе Импорт произвольного исходного файла Python. (Python 3.3+) и одно из решений, которое появилось там:
>>> loader = importlib.machinery.SourceFileLoader(name, filepath)
>>> mod = types.ModuleType(loader.name)
>>> loader.exec_module(mod)
>>> mod.__version__
1.0.0
2 ответа
Если вы просто хотите импортировать версию, я обычно выбираю utils
которые предлагаются от werkzeug
; Я считаю, что вы можете использовать следующее:
from werkzeug.utils import import_string
version = import_string('module.__version__', silent=True)
Вы также можете пройти silent
как bool
, который скажет функции игнорировать ошибки импорта и возвращать None
если возникнут какие-либо ошибки.
"Удобный" способ импортировать модуль - это использовать importlib.import_module()
, Это для всех практических целей, так же, как использование import
заявление. Тем не менее, он не может импортировать произвольные файлы, которые не находятся в sys.path
, так что это не работает для вашего варианта использования.
Чтобы импортировать файл напрямую, importlib
Документация содержит этот рецепт:
import importlib.util import sys # For illustrative purposes. import tokenize file_path = tokenize.__file__ module_name = tokenize.__name__ spec = importlib.util.spec_from_file_location(module_name, file_path) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) # Optional; only necessary if you want to be able to import the module # by name later. sys.modules[module_name] = module
Наконец, несколько советов: я рекомендую поместить строку версии в отдельный текстовый файл (скажем) __version__.txt
и загружая его из __init__.py
и все остальное, что нужно знать версию. Таким образом, вам не нужно выполнять код Python для чтения номера версии. Вы можете загрузить данные из таких файлов, используя pkgutil.get_data(__package__, '__version__.txt')
в __init__.py
и заменить __package__
с подходящим значением при вызове из другого модуля или откройте файл напрямую. get_data()
возвращается bytes
; вы можете позвонить .decode()
на возвращаемое значение, чтобы преобразовать его в строку.
(pkgutil.get_data()
Это может показаться окольным путем, но это необходимо, если ваш код импортирован из ZIP-файла или установлен каким-либо другим экзотическим способом. Если ваш код находится в пакете пространства имен или был установлен необычным образом, get_data()
может не работать и вернуться None
, поэтому вы должны проверить этот случай и избежать сбоев.)