Getting Python package distribution version from within a package

后端 未结 3 1192
灰色年华
灰色年华 2021-01-05 23:53

You can get the version of a python distribution using

import pkg_resources
pkg_resources.get_distribution(\"distro\").version

This is grea

3条回答
  •  独厮守ぢ
    2021-01-06 00:19

    If you're looking for a solution that works both from your development—not installed, or just locally called—version, and an installed version, then try this solution.

    Imports:

    import ast
    import csv
    import inspect
    from os import listdir, path
    
    import pkg_resources
    

    Utility function:

    def get_first_setup_py(cur_dir):
        if 'setup.py' in listdir(cur_dir):
            return path.join(cur_dir, 'setup.py')
        prev_dir = cur_dir
        cur_dir = path.realpath(path.dirname(cur_dir))
        if prev_dir == cur_dir:
            raise StopIteration()
        return get_first_setup_py(cur_dir)
    

    Now using Python's ast library:

    def parse_package_name_from_setup_py(setup_py_file_name):
        with open(setup_py_file_name, 'rt') as f:
            parsed_setup_py = ast.parse(f.read(), 'setup.py')
    
        # Assumes you have an `if __name__ == '__main__':`, and that it's at the end:
        main_body = next(sym for sym in parsed_setup_py.body[::-1]
                         if isinstance(sym, ast.If)).body
    
        setup_call = next(sym.value
                          for sym in main_body[::-1]
                          if isinstance(sym, ast.Expr) and
                          isinstance(sym.value, ast.Call) and
                          sym.value.func.id in frozenset(('setup',
                                                          'distutils.core.setup',
                                                          'setuptools.setup')))
    
        package_version = next(keyword
                               for keyword in setup_call.keywords
                               if keyword.arg == 'version'
                               and isinstance(keyword.value, ast.Name))
    
        # Return the raw string if it is one
        if isinstance(package_version.value, ast.Str):
            return package_version.s
    
        # Otherwise it's a variable at the top of the `if __name__ == '__main__'` block
        elif isinstance(package_version.value, ast.Name):
            return next(sym.value.s
                        for sym in main_body
                        if isinstance(sym, ast.Assign)
                        and isinstance(sym.value, ast.Str)
                        and any(target.id == package_version.value.id
                                for target in sym.targets)
                        )
    
        else:
            raise NotImplemented('Package version extraction only built for raw strings and '
                                 'variables in the same function that setup() is called')
    

    Finally replace the function in @Gricey's answer by changing return "development" to:

    return parse_package_name_from_setup_py(get_first_setup_py(path.dirname(__file__)))
    

    Taken from my answer https://stackoverflow.com/a/60352386

提交回复
热议问题