Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get the current 'package' name? (setup.py)

How do I get the current topmost package, i.e., the name defined in setup.py?

Here is my tree:

.
|-- README.md
|-- the_project_name_for_this_pkg
|   |-- __init__.py
|   |-- __main__.py
|   |-- _config
|   |   `-- foo.conf
|   |-- _data
|   |   `-- logging.yml
|   `-- tests
|       |-- __init__.py
|       `-- test_foo.py   <--- # executing from here
|-- requirements.txt
`-- setup.py

4 directories, 9 files

The only solution I've gotten to work so far is this:

import os
import sys


os.path.basename(sys.path[1])

But this is obviously a bad solution. Other solutions like having a __name__ in my uppermost __init__.py file and using ast.parse to read in the relevant section of setup.py also seems cumbersome.

Other solutions I've tried—by calling them within a unittest.TestCase inheriting class in my tests python [sub]package—include checking sys.modules[__name__], inspect.getmodule & inspect.stack, as well as the answers to these questions:

  • Python - Get path of root project structure
  • Get full package module name
  • Get fully qualified class name of an object in Python
  • How can I access the current executing module or class name in Python?
  • Get full caller name (package.module.function) (Python recipe)
  • https://docs.python.org/2/library/modulefinder.html

BTW: In case you were wondering why I want the package name… it's so I can run things like:

import pkg_resources


version   = pkg_resources.require('the_project_name_for_this_pkg')[0].version
data_file = path.join(resource_filename('the_project_name_for_this_pkg', '__init__.py'),
                      '_config', 'data_file.txt')
like image 720
A T Avatar asked Feb 22 '20 10:02

A T


1 Answers

Not entirely sure what the larger goal is, but maybe you could be interested in reading about importlib.resources as well as importlib.metadata.

Something like the following:

import importlib.metadata
import importlib.resources

version = importlib.metadata.version('SomeProject')
data = importlib.resources.files('top_level_package.sub_package').joinpath('file.txt').read_text()

And more generally, it is near impossible (or not worth the amount of work) to 100% reliably detect the name of the project (SomeProject) from within the code. It is easier to just hard-code it.

Nevertheless here are some techniques, and ideas to retrieve the name of the project from one of its modules:

  • https://bitbucket.org/pypa/distlib/issues/102/getting-the-distribution-that-a-module
  • https://stackoverflow.com/a/22845276/11138259
  • https://stackoverflow.com/a/56032725/11138259

Update:

I believe some function like the following should return the name of the installed distribution containing the current file:

import pathlib
import importlib_metadata

def get_project_name():
    for dist in importlib_metadata.distributions():
        try:
            relative = pathlib.Path(__file__).relative_to(dist.locate_file(''))
        except ValueError:
            pass
        else:
            if relative in dist.files:
                return dist.metadata['Name']
    return None

Update (February 2021):

Looks like this could become easier thanks to the newly added packages_distributions() function in importlib_metadata:

  • https://importlib-metadata.readthedocs.io/en/stable/using.html#package-distributions
  • https://github.com/python/importlib_metadata/pull/287/files
like image 164
sinoroc Avatar answered Sep 25 '22 10:09

sinoroc