Get function import path
Asked Answered
D

3

23
from pack.mod import f

How to get from object f information about import - 'pack.mod'

I can get it using f.__module__ but if function def in module where i get this attribute (f.__module__) it return '__main__'. But i need real path here - 'pack.mod'

I found this way to get this information:

inspect.getmodule(f).__file__

then i can sub start path from sys.path, replace / on . and get path like - 'pack.mod' But may be exist some more convenient way?

Dedededen answered 10/3, 2010 at 18:17 Comment(1)
why do you need this to begin with?Sisk
G
21

What inspect.getmodule(f) does internally, per inspect.py's sources, is essentially sys.modules.get(object.__module__) -- I wouldn't call using that code directly "more convenient", though (beyond the "essentially" part, inspect has a lot of useful catching and correction of corner cases).

Why not call directly inspect.getsourcefile(f)?

Edit: reading between the lines it seems the OP is trying to do something like

python /foo/bar/baz/bla.py

and within bla.py (which is thus being run as __main__) determine "what from or import statement could a different main script use to import this function from within me?".

Problem is, the question is ill-posed, because there might not be any such path usable for the purpose (nothing guarantees the current main script's path is on sys.path when that different main script gets run later), there might be several different ones (e.g. both /foo/bar and /foo/bar/baz might be on sys.path and /foo/bar/baz/__init__.py exist, in which case from baz.bla import f and from bla import f might both work), and nothing guarantees that some other, previous sys.path item might not "preempt" the import attempt (e.g., say /foo/bar/baz is on sys.path, but before it there's also /fee/fie/foo, and a completely unrelated file /fee/fie/foo/bla.py also exists -- etc, etc).

Whatever the purpose of this kind of discovery attempt, I suggest finding an alternative architecture -- e.g., one where from baz.bla import f is actually executed (as the OP says at the start of the question), so that f.__module__ is correctly set to baz.bla.

Grooms answered 10/3, 2010 at 18:34 Comment(4)
OK, but i need some native way to get info in format ready for importing, not file path witch i need to parse for extract info. It exists or i must parse path anyway?Dedededen
The __module__ attribute gives you that path -- you claim it gives __main__, but that will never happen when you've done, as you also say, from path.mod import f -- only if you're running the file as the main script instead of importing it, and that from statement means you are importing and so __module__ works fine.Grooms
My goal to write logger. i hang it on function as decorator. It dumps all function args it called with at db, function name and module name also written - i need this information to restore function call later with this args on demand. To restore call i need load function before, and that why i need path to load it... I'am targeting that sys.path always same. Mb i need some another way to identify how to load function, m.b full file path and function name better...but in this case i need to analyze file path and sys.path to build valid import path...is it right?Dedededen
If the function is defined in __main__ when you log it, it had better be defined exactly the same place when you restore it (i.e, you clearly need to be running the same main script as well as having the same sys.path), so from __main__ import f in this case is the right answer. No other "path" except __main__ can ever possibly guarantee it will load the same function that __main__ has defined, as I explained. So just use the __module__, whether it's __main__ or anything else, for your now-stated purposes.Grooms
B
11

You want the __name__ attribute from __module__:

In [16]: import inspect
In [17]: inspect.getmodule(MyObject).__name__
Out[17]: 'lib.objects.MyObject'
Benelux answered 10/9, 2013 at 6:53 Comment(1)
I'm a little surprised by your answer, I think the snippet isn't correct, it doesn't seem to be possible to get the result you are given, no matter if MyObject is a class (as the capitalization suggests) or a object instance (as the name suggests). See below.Burushaski
B
0

I think that Will's answer above https://mcmap.net/q/563223/-get-function-import-path is incorrect, as commented:

cd /tmp/
mkdir test
cd test
mkdir lib
echo "class MyObject: pass" > lib/objects.py
touch lib/__init__.py
export PYTHONPATH=.
python3 -c 'import inspect; from lib.objects import MyObject; print(inspect.getmodule(MyObject).__name__)'

outputs:

lib.objects

and if I replace the from lib.objects import MyObject with from lib.objects import MyObject as MyObjectClass; MyObject = MyObjectClass(), I get the same results.

Burushaski answered 5/2, 2022 at 4:52 Comment(1)
It's breaking changes in Python. to get the function/module's name MyObject.__name__ or obj = MyObject; obj.__name__Noahnoak

© 2022 - 2024 — McMap. All rights reserved.