How to dynamically load modules when importing packages?

Given the following example layout:

test/
  test.py
  formats/
    __init__.py
    format_a.py
    format_b.py

I'm trying to back up that whenever I import formats, __init__.pylooking for all available modules poddirete formats, downloads them and makes them available (right now just by variable supported_formats). If theres better, more pythonic or otherwise suitable for dynamically loading material at runtime, based on the physical files available, please advise.

My approach

I tried something like this (in __init__.py):

supported_formats =  [__import__(f[:f.index('.py')]) for f in glob.glob('*.py')]

So far, I just make it work when I run it __init__.pyfrom the command line (from the subdir format or from other directories). But when I import it from test.py, it attacks me as follows:

ImportError: No module named format_a.py

, python, , formats.

. dict, - , :

def dload(get_cls=True, get_mod=True, key=None, fstring_mod='*.py', fstring_class=''):
  if p.dirname(__file__):
    path = p.split(p.abspath(__file__))[0]
    fstring_mod = p.join(path, fstring_mod)
    print >> sys.stderr, 'Path-Glob:', fstring_mod
  modules = [p.split(fn)[1][:fn.index('.py')] for fn in glob.glob(fstring_mod)]
  print >> sys.stderr, 'Modules:', ', '.join(modules)
  modules = [__import__(m) for m in modules]
  if get_cls:
    classes = {} if key else []
    for m in modules:
      print >> sys.stderr, "-", m
      for c in [m.__dict__[c]() for c in m.__dict__ if c.startswith(fstring_class)]:
        print >> sys.stderr, " ", c
        if key:
          classes[getattr(c, key)] = c
        else:
          classes.append(c)
    if get_mod:
      return (modules, classes)
    else:
      return classes
  elif get_mod:
    return modules

_supported_formats = dload(get_mod=False, key='fid', fstring_mod='format_*.py', fstring_class='Format')

.., , . - , , , .

+3
5

:

  • __import__(m, globals(), locals()) __import__(m). , Python .

  • .py , index() . .py, p.split(fn)[1][:-3] .

+1

, . __file__. .

, - (untested):

supported_formats = {}
for fn in os.listdir(os.path.dirname(__file__)):
    if fn.endswith('.py'):
        exec ("from formats import %s" % fn[:-3]) in supported_formats
+1

sys.path . sys.path . , sys.path 'module.py', , ".py" .

, , , , , .

0

I thought that if you did something, the β€œformats” would be your package, so when you tell it import formatsyou can access the rest of the modules inside this package, so you will have something likeformats.format_a.your_method

Not sure though, I'm just n00b.

0
source

Here is the code I came up with after corrections from interjay. Still not sure if this is a good style.

def load_modules(filemask='*.py', ignore_list=('__init__.py', )):
  modules = {}
  dirname = os.path.dirname(__file__)
  if dirname:
    filemask = os.path.join(dirname, filemask)
  for fn in glob.glob(filemask):
    fn = os.path.split(fn)[1]
    if fn in ignore_list:
      continue
    fn = os.path.splitext(fn)[0]
    modules[fn] = __import__(fn, globals(), locals())
  return modules
0
source

Source: https://habr.com/ru/post/1727276/


All Articles