classification
Title: How to search for a __main__ module using pyclbr in Python3?
Type: behavior Stage:
Components: Library (Lib) Versions: Python 3.8
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: kebab-mai-haddi, kxrob
Priority: normal Keywords:

Created on 2021-02-18 03:16 by kebab-mai-haddi, last changed 2021-02-22 18:14 by kxrob.

Messages (2)
msg387200 - (view) Author: Aviral Srivastava (kebab-mai-haddi) Date: 2021-02-18 03:16
I want to get all the functions and classes in module: `__main__` of the source code directory: `/tmp/rebound/rebound`. 
When I use the `pyclbr.readmodule_ex` API:
```
source_code_data = pyclbr.readmodule_ex(source_code_module, path=source_code_path)
```
I specify it the module and it's path:
```
DEBUG:root:Source code module: __main__, Source code path: ['/tmp/rebound/rebound/rebound']
```
I then get this error:
```
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/importlib/util.py", line 69, in _find_spec_from_path
    raise ValueError('{}.__spec__ is None'.format(name))
ValueError: __main__.__spec__ is None
```
I then tried to use the function that is not supposed to be used by the public: `_readmodule`:
```
source_code_data = pyclbr._readmodule(source_code_module, source_code_path, )
```
But I could not decide what should be the value of the parameter: `inpackage`.

Upon tracing the code via debugger, I spotted a mistake:
```
def _find_spec_from_path(name, path=None):
    """Return the spec for the specified module.

    First, sys.modules is checked to see if the module was already imported. If
    so, then sys.modules[name].__spec__ is returned. If that happens to be
    set to None, then ValueError is raised. If the module is not in
    sys.modules, then sys.meta_path is searched for a suitable spec with the
    value of 'path' given to the finders. None is returned if no spec could
    be found.

    Dotted names do not have their parent packages implicitly imported. You will
    most likely need to explicitly import all parent packages in the proper
    order for a submodule to get the correct spec.

    """
    if name not in sys.modules:
        return _find_spec(name, path)
    else:
        module = sys.modules[name]
        if module is None:
            return None
        try:
            spec = module.__spec__
        except AttributeError:
            raise ValueError('{}.__spec__ is not set'.format(name)) from None
        else:
            if spec is None:
                raise ValueError('{}.__spec__ is None'.format(name))
            return spec
```
This is the function in the module: `python3.8/importlib/util.py` and it evaluates `__main__` as a built-in module as it falls in the `else` block.

How do I differentiate `__main__` of my target source code to read from the built-in `__main__`? In other words, how do I read the module `__main__` of the codebase: rebound?
msg387524 - (view) Author: Robert (kxrob) * Date: 2021-02-22 18:14
#  `__main__` of the source code directory: `/tmp/rebound/rebound`. 
#  differentiate `__main__` of my target source code to read from the built-in `__main__`? In other words, how do I read the module `__main__` of the codebase: rebound?

=> when __main__.py is inside a package, use the full dotted module name - and an appropriate search path below that directory:

pyclbr.readmodule_ex('rebound.__main__')
pyclbr.readmodule_ex('lib2to3.__main__')

When __main__.py is intended as a top level module / script, I think such a name collision with an internal module name is a bad idea at all.
(For a special local purposes you could use a symlink or so?)


(I experience a bug with pyclbr (in py3.10 at least) when it traverses an "import __main__" statement. It causes also "ValueError: __main__.__spec__ is None" or "ValueError: {}.__spec__ is not set".  But this seems to be an actual bug w/o bug report so far: #43299 )
History
Date User Action Args
2021-02-22 18:14:03kxrobsetnosy: + kxrob
messages: + msg387524
2021-02-18 03:16:48kebab-mai-haddicreate