2

I have a setup.py file like this (not in pwd, not in Python path, a random file somewhere):

import ext_modules

config = {
    'name': 'mesos.executor',
    'version': '1.4.1',
    'description': 'Mesos native executor driver implementation',
    'author': 'Apache Mesos',
    'author_email': 'dev@mesos.apache.org',
    'url': 'http://pypi.python.org/pypi/mesos.executor',
    'namespace_packages': [ 'mesos' ],
    'packages': [ 'mesos', 'mesos.executor' ],
    'package_dir': { '': 'src' },
    'install_requires': [ 'mesos.interface == 1.4.1' ],
    'license': 'Apache 2.0',
    'keywords': 'mesos',
    'classifiers': [ ],
    'ext_modules': [ ext_modules.executor_module ]
}

from setuptools import setup
setup(**config)

And from an external (Python) script I'd like to import config["install_requires"]. I'm looking for the most minimalist way of doing this as it's intended to be run from other scripts that might even not be Python.

A Python one-liner would be awesome.

georgexsh
  • 15,984
  • 2
  • 37
  • 62
Adam C.
  • 23
  • 6

2 Answers2

2

Aside from importing python module from an arbitrary path, you also need to avoid execute setup(), one method is filtering through AST:

import ast, _ast

def filter_setup_st(node):
    if isinstance(node, _ast.Expr) and isinstance(node.value, _ast.Call):
        if node.value.func.id == 'setup':
            return False
    return True

with open('/path/to/example_setup.py') as f:
    c = f.read()   
tree = ast.parse(c)
tree.body = [n for n in tree.body if filter_setup_st(n)]

ns = {}
exec(compile(tree, '__string__', 'exec'), {}, ns)

assert ns['config']['install_requires'] == ['mesos.interface == 1.4.1']

another method is a bit tricky, to nullify setuptools.setup temporarily:

import setuptools
ori_setup = setuptools.setup
setuptools.setup = lambda *a, **k: 0

ns = {}
exec(compile(c, '__string__', 'exec'), {}, ns)
assert ns['config']['install_requires'] == ['mesos.interface == 1.4.1']

setuptools.setup = ori_setup

Update:

In case you also want bypass import of ext_modules:

import sys

class fake_ext_module():

    executor_module = 'spam'

sys.modules['ext_modules'] = fake_ext_module
georgexsh
  • 15,984
  • 2
  • 37
  • 62
  • Really like the hacky second method that actually kinda works. However, one of the setup.py tries to import an external module which fails because I'm not loading from the expected folder. Do you think I can also "nullify" import ? – Adam C. Nov 28 '17 at 18:48
1

In the doc : https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly

In your case:

import importlib
setup_file = "path/to/setup.py"
spec = importlib.util.spec_from_file_location("setup", setup_file)
setup = importlib.util.module_from_spec(spec)
spec.loader.exec_module(setup)
# And now access it
print(setup.config["install_requires"])
Adrien Logut
  • 812
  • 5
  • 13
  • I'm pretty sure I'll have issue with the setup() method being called when importing the file – Adam C. Nov 28 '17 at 18:47
  • 1
    I understand, but a work around would be to encapsulate the command: `def do_setup(): from setuptools import setup setup(**config)` And then `if __name__ == "__main__": do_setup()` – Adrien Logut Nov 28 '17 at 18:58