0

I'm writing a small utility function which takes in input arguments of the location of a Python file, and also a function to call within the Python file

For example src/path/to/file_a.py

def foo():
  ...

In the utility function, I'm parsing the arguments like so:

python ./util.py --path src/path/to/file_a.py --function foo

and the foo function needs to be used later in the util.py in another library:

def compile():
  compiler.compile(
    function=foo,
    etc
  )

What's the best way of importing the foo function via argparse?


Some initial thoughts:

util.py:

def get_args():
  parser = argparse.ArgumentParser()
  parser.add_argument("--path", type=str)
  parser.add_argument("--function", type=str)
  return parser.parse_args()

def compile(path, function):
  import path 
  compiler.compile(
    function=path.function,
    etc
  )

if __name__ == "__main__":
  args = get_args()
  compile(
    path=args.path
    function=args.function
  )

however importing via argparse, and adding it to the function does not seem to work nicely.

There's also the idea of using sys.path.append:

def compile(path, function):
  import sys
  sys.path.append(path)

but then I'm unsure of how to import the foo function from that.

Rekovni
  • 6,319
  • 3
  • 39
  • 62
  • State the actual error, not a vague 'does not work'. All `arparse` can do for you is get the two strings. What you do with the strings is not part of `argparse` – hpaulj Jan 24 '23 at 16:08

1 Answers1

1

This problem can be rephrased as "how do I import a python file given a path?" To do that, we can use https://stackoverflow.com/a/67692/5666087. Here is a code example that incorporates the answer to that question with your needs.

import argparse
import importlib.util
import sys


def get_function_object(path_to_pyfile: str, funcname: str):
    spec = importlib.util.spec_from_file_location("tmpmodulename", path_to_pyfile)
    module = importlib.util.module_from_spec(spec)
    sys.modules["tmpmodulename"] = module
    spec.loader.exec_module(module)
    if not hasattr(module, funcname):
        raise AttributeError(f"Cannot find function '{funcname}'in imported module")
    # TODO: Consider testing whether this object is a callable.
    return getattr(module, funcname)


def get_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("--path", type=str)
    parser.add_argument("--function", type=str)
    return parser.parse_args()


if __name__ == "__main__":
    args = get_args()
    function = get_function_object(args.path, funcname=args.function)
    compiler.compile(function=funtion)
jkr
  • 17,119
  • 2
  • 42
  • 68