Python Forum
importing a module given a path to the file
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
importing a module given a path to the file
#1
i want to have my script take a path to a file that it gets (may be typed in, or read from some other file, or given as a command argument) and import it as a module without any copying and/or renaming of files. i vaguely remember that i saw, a few years ago, a function that maybe could do this, but i cannot recall what it is or where i saw it, now that i need it. any ideas?
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply
#2
I have written such functions. Use them freely: I declare them to be under the MIT license
# SPDX-FileCopyrightText: 2023 Eric Ringeisen
# SPDX-License-Identifier: MIT

def import_from_source_file(module_name, file_path):
    """Import a source file as a module
    
    Arguments:
        @module_name: the qualified name of the module
        @file_path: the path to the file containing the module's code
        
    If a module with that name already exists in sys.modules,
    nothing is done and the existing module is returned.
    
    This function does not attempt to import the parent module
    nor to insert it in sys.modules.
    """
    from pathlib import Path
    import sys
    try:
        return sys.modules[module_name]
    except KeyError:
        pass
    # from a recipe in importlib.machinery's documentation
    import importlib.util
    if Path(file_path).is_dir():
        file_path = str(Path(file_path)/'__init__.py')
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    if spec is None:
        raise ImportError(
            'Cannot get module spec from file location', file_path)
    module = importlib.util.module_from_spec(spec)
    sys.modules[module_name] = module
    spec.loader.exec_module(module)
    return module

def import_tree(root_name, tree):
    """Import a tree of files as submodules of a root module
    
    Arguments:
        @root_name: the qualified name of module
        @tree: a dictionary mapping keys to path to files or similar
            dictionaries
    
    Returns:
        the root module or None if root_name is ''
    
    Example:
        The call
        
        import_tree('spam', {
            'foo': 'bar.py',
            'baz': {'x': 'tmp/xxx.py', 'y': 'yy32.py'},
            'qux': 'qux/quux.py'})
            
        will create the modules
        
            spam
            spam.foo (from file bar.py)
            spam.baz
            spam.baz.x (from file tmp/xxx.py)
            spam.baz.y (from file yy32.py)
            spam.qux (from file qux/qyyx.py)
        
        These modules are inserted in sys.modules.
        Any already existing modules are not created.
    """
    from importlib import import_module
    import sys
    from types import ModuleType
    if root_name:
        try:
            root = import_module(root_name)
        except ImportError:
            root = sys.modules[root_name] = ModuleType(root_name)
    else:
        root = None
    def handle(mod, prefix, key, value):
        s = key if not prefix else (prefix + '.' + key)
        try:
            m = import_module(s)
        except ImportError:
            if isinstance(value, dict):
                m = sys.modules[s] = ModuleType(s)
            else:
                m = import_from_source_file(s, value)
            if mod:
                setattr(mod, key, m)
        if isinstance(value, dict):
            for k, v in value.items():
                handle(m, s, k, v)
    for key, value in tree.items():
        handle(root, root_name, key, value)
    return root
Reply
#3
how much of that file is the important stuff plus what else it needs to work vs. how much of that file is sample code to show how to use it?

i figured out a way to accomplish my need without importing a module. my need is to read in a file that sets many variables with values that can be expressed in Python, including expressions that can involve previously set variables. what this way does is read in the code as a big string and call the builtin exec() function. what exec() returns is the dictionary i wanted to derive from that file of assignments.

initially, i thought importing the file as a module would be most direct though i would still need to get the assigned values out of it. then i though o using exec to import it by name by making the import statement code. while thinking over how to do that in various paths, it became clear that by just reading the file at that path, exec() does all i need.

while playing with an implementation, i found i could set values in the exec() global space and have assignments in the file get values from variable names so the files do not all need literals.

i am using this to create config files for a few scripts i am developing to manage various resources in the AWS cloud. the first reason i went with using Python code was to be able to do multi-line triple-quoted values, such as quoting a few lines to hold a list of resources or a script to run in a cloud instance".
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply
#4
(Oct-29-2023, 11:08 PM)Skaperen Wrote: how much of that file is the important stuff plus what else it needs to work vs. how much of that file is sample code to show how to use it?
There is no sample code in that file. It contains only two functions. One of them allows one to import a python file as one would import a module, in a way that is compatible with Python's importlib mechanism. The other one allows one to import a bunch of python files as a tree of modules and submodules.

Of course, a simple exec may address your needs if you don't need to fill a module with this code.
(Oct-29-2023, 11:08 PM)Skaperen Wrote: i am using this to create config files for a few scripts i am developing to manage various resources in the AWS cloud.
I'm currently writing a library to manage configuration files. I'll make an announcement on this forum when it is ready to be used!
Reply
#5
(Oct-30-2023, 05:19 AM)Gribouillis Wrote: I'm currently writing a library to manage configuration files. I'll make an announcement on this forum when it is ready to be used!
will it allow a variety of different kinds of "config" files?

i have been using Python3 as my config file language by importing it as a module. i have been play with adding a number of tools to this. now it seem exec() might be a better way to go. i can pre-set variables for config files to use instead of literals. with import i have to add them to the config file and save it as a temporary. with exec() i can pass a dictionary in argument 2 and they don't get included in the return dictionary. exec() seems to be the clean way to go.

my latest project involves managing multiple projects and sub-projects where each might need config info for individual projects with variable inheritance from parent projects.
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply
#6
(Nov-01-2023, 01:01 AM)Skaperen Wrote: will it allow a variety of different kinds of "config" files?
Yes it will be extensible with an arbitrary number of configuration 'protocols'. Currently I have 3 protocols, one is 'configparser' and another one is called 'methodic' and it is a pure python protocol. But the library will be easily extensible to other protocols such as 'json' or 'yaml' or your own custom protocols.
(Nov-01-2023, 01:01 AM)Skaperen Wrote: my latest project involves managing multiple projects and sub-projects where each might need config info for individual projects with variable inheritance from parent projects.
I'm working hard to finish my library. I'm sure it could help you. The library's main feature is that you are free to store configuration files anywhere in the file system, potentially even inside zip files or databases. I've been using a very preliminary version of this library for two years now and the concept is pleasantly flexible.
Reply
#7
(Oct-30-2023, 05:19 AM)Gribouillis Wrote: I'm currently writing a library to manage configuration files. I'll make an announcement on this forum when it is ready to be used!
will it have a Python API?
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply
#8
(Nov-02-2023, 07:37 PM)Skaperen Wrote: will it have a Python API?
Yes it is pure Python code with an API and a command line interface.
Reply
#9
i still like to write config files in Python. so, i'd like to have some kind of support for that. it needs to have a way to be controlled for security in cases where the config or data it uses comes from untrusted sources like a web query. advantages include:

1. config settings can have relations between each other such as a number setting that is 3 times plus 72 more than another number setting or a string that is the same as part of another.

2. the ease of a multi-line string that triple-quoting has.

3. accessing information from the file system or other files to establish settings.

4. the ability to do calculations that ordinary config files cannot do.
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  max component length of file path name Skaperen 1 1,099 Jun-19-2022, 04:03 AM
Last Post: Larz60+
  file system path representation Skaperen 7 3,683 Mar-03-2021, 02:12 AM
Last Post: Skaperen

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020