简体   繁体   中英

Fetch __version__ value from file without using imp.load_source?

I have previously done the following to fetch a version string:

>>> filepath = './somemodule/__init__.py'
>>> name = 'dummy'
>>> module_source = imp.load_source(name, filepath)
>>> module_source.__version__
1.0.0

Now, when imp has been deprecated in Python 3 (I'm on 3.7.1), what would be a nice replacement for load_source which will just require the std library?

This seems a little convoluted to me AND load_module is actually deprecated:

>>> from importlib.machinery import SourceFileLoader
>>> loaded = SourceFileLoader(name, filepath).load_module()
>>> loaded.__version__
1.0.0

EDIT #1:

This is discussed in Import arbitrary python source file. (Python 3.3+) and one of the solutions which came up there is:

>>> loader = importlib.machinery.SourceFileLoader(name, filepath)
>>> mod = types.ModuleType(loader.name)
>>> loader.exec_module(mod)
>>> mod.__version__
1.0.0

If you're simply looking to import the version, I usually opt to use utils that are offered from werkzeug ; I believe you can use the following:

from werkzeug.utils import import_string
version = import_string('module.__version__', silent=True)

You can also pass silent as a bool , which will tell the function to ignore import errors and return None if any errors are encountered.

The "comfortable" way to import a module is to use importlib.import_module() . This is, for all practical purposes, just like using the import statement. However, it cannot import arbitrary files which are not in sys.path , so it doesn't work for your use case.

To import a file directly, the importlib documentation provides this recipe:

 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 

Finally, a bit of advice: I recommend putting the version string in a separate text file called (say) __version__.txt , and loading it from __init__.py and anything else which needs to know the version. That way, you don't need to execute Python code to read the version number. You can load data from such files by using pkgutil.get_data(__package__, '__version__.txt') in __init__.py , and replace __package__ with a suitable value when calling from another module, or open the file directly. get_data() returns bytes ; you may want to call .decode() on the return value to convert it into a string.

( pkgutil.get_data() may seem a roundabout way to do it, but it's required if your code is imported from a ZIP file or installed in some other exotic way. If your code is in a namespace package or was installed in a particularly unusual fashion, get_data() may fail to work and return None , so you should check for that case and avoid crashing on it.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM