diff --git a/lib/python/xconv/profile.py b/lib/python/xconv/profile.py index b12bdfb..70fe1fb 100644 --- a/lib/python/xconv/profile.py +++ b/lib/python/xconv/profile.py @@ -25,7 +25,7 @@ xconv ffmpeg wrapper based on AdvancedAV Decorators for defining xconv profiles """ -from .profileman import index +from .profileman import index, make_qname from functools import wraps @@ -39,6 +39,7 @@ __all__ = [ "singleaudio" ] + # == Misc. helpers == def __update(f, name, update): if hasattr(f, name): @@ -65,7 +66,7 @@ def profile(f): ext=None, defines={}, features={}) - index[f.__name__] = f + index[make_qname(f.__module__, f.__name__)] = f return f diff --git a/lib/python/xconv/profileman.py b/lib/python/xconv/profileman.py index ff540c6..0f8e732 100644 --- a/lib/python/xconv/profileman.py +++ b/lib/python/xconv/profileman.py @@ -32,33 +32,85 @@ from pathlib import Path # == Profile Index == index = {} +profiles_package = __package__ + ".profiles" + + +def make_qname(module, name): + """ + Create a qualified name for a profile + """ + # The global profiles package is omitted from the front + if module.startswith("%s." % profiles_package): + module = module[len(profiles_package) + 1:] + # But arbitrary packages can be specified by prepending : + # This, among other things, allows to use profiles defined + # in .py files in the working dir. + else: + module = ":" + module + + # If it's not deeply nested and the module name + # and profile name are the same, the latter + # can be omitted. + if module.strip(":") != name: + return "%s.%s" % (module, name) + else: + return module + + # Examples: + # Profile xconv.profiles.opus/opus: + # - opus + # - opus.opus + # - :xconv.profiles.opus.opus + # Watch out for xconv.profiles/opus (not valid): + # - :xconv.profiles.opus + # Profile xconv.profiles.opus/stuff: + # - opus.stuff + # - :xconv.profiles.opus.stuff + # Profile test/test: + # - :test + # - :test.test + def load_profile(name): + """ + Find and load a XConv profile. + """ + # Check if it's already loaded if name in index: return index[name] - try: - import_module(".profiles.%s" % name, __package__) - except ImportError as e: - print(e) - pass + # See if it's a qualified name + module = name.rsplit(".", 1)[0] if "." in name[1:] else name - if name in index: - return index[name] + # Check if it's in the global profiles package or not + if module[0] == ":": + module = module[1:] + else: + module = "." + module - load_all_profiles() + # Try to import the module + import_module(module, profiles_package) - if name in index: + # Return the profile + try: return index[name] - - raise ImportError("Could not find XConv profile '%s'" % name) + except KeyError: + # Fully qualifying the global profiles package is technically valid. + if name.startswith(":%s." % profiles_package): + qname = make_qname(*name[1:].rsplit(".", 1)) + if qname in index: + return index[qname] + raise ImportError("Module %s doesn't contain XConv profile %s" % (module, name)) def load_all_profiles(): + """ + Load all profile definitions + """ for location in profilepaths: for mod in (x for x in Path(location).iterdir() if x.is_file() and x.suffix == ".py"): try: - import_module(".profiles.%s" % mod.stem, __package__) + import_module(".%s" % mod.stem, profiles_package) except ImportError: pass