For example, i have 2 .py files module1 and module2.
module2 imports module1 using the import statement.
I want to have some way inside the module1 to detect (from within the module1 itself) which modules importing it. in this case the module2 is importing it.
There is a way to determine within a function what function called the function (but is could be that the caller is a module). This involves looking back at the stack of execution frames, but I have never done this. There may be a function in inspect that helps with this. Look there.
import ast
import inspect
def dprn(*iargs, sep="\n"):
"""
Goal of this function is to detect the lvalues of the arguments
passed to it and then print the passed rvalue as it is in this
form, <<- detected_lvalue: rvalue ->> respecting the sep argument.
Currently it works only if the caller is on the same module
because eval cant get the rvalue of a lvalue if its on a separate
module, but, i want it to put on a myutils module, and want to
import it to any module and use it. in future I may modify it to
be a decorator.
"""
### -0- detect from which module this func is being called
cmf = next(reversed(inspect.stack())).frame.f_globals["__file__"]
### -0-
with open(cmf, mode="r", encoding="utf-8") as f:
ap = ast.parse(f.read())
### -1- dumping the full ast node tree for manual inspection
cadf = f"{cmf[0:(cmf.rfind('/'))]}/castd.txt"
with open(cadf, mode="wt", encoding="utf-8") as df:
df.write(ast.dump(ap, indent=4))
### -1-
for cn in ast.walk(ap):
if type(cn) is ast.Call:
if type(cn.func) is ast.Name:
if cn.func.id == "dprn":
#print(f"cnd={ast.dump(cn)}\n")
avl, anl, cnt = [], [], 0
for cfa in cn.args:
#print(f"cfa_d={ast.dump(cfa)}\n")
can_up = ast.unparse(cfa)
#print(can_up)
try:
### -2- trying to find the rvalue
# of the current lvalue. but
# eval will not work if the caller
# is on a different module then
# this dprn function. I need to
# find a way to get the rvalue
# of a lvalue which is in a
# different module. I need this
# because of the current caller
# detection logic bellow.
# for theres a different detection
# logic, i may not need this.
can_ev = eval(can_up)
### -2-
except NameError:
can_ev = "NA"
avl.append(can_ev)
if type(cfa) is ast.Name:
anl.append(can_up)
else:
anl.append(f"und{cnt}")
cnt += 1
#print(f"avl={avl}")
avl = tuple(avl)
### -3- current caller detection
# but will not work if different
# lvalues have the same rvalue.
if avl == iargs: #detection logic
### -3-
lnl = len(sorted(anl, key=lambda e: len(e), reverse=True)[0])
for n, v in zip(anl, avl):
print(f"{n}{' '*(lnl-len(n))}: {v}", end=sep)
short answer is yes. and the long answer is if this func is on the same module as the caller then i dont need that but if both on a separate module and use the func by importing it then yes I do need to know which module called the func because ast to make the node tree needs the source code.
@indrajit The question is broader. Why are you doing any of this in the first place? What is the actual problem you want to solve, independent of any potential implementation? We ask, because all of this is extraordinary unusual, fragile, and error-prone. If you share your actual problem or motivation, then perhaps there is an entirely different solution we can suggest, that doesn’t involve this highly unorthodox approach.
i have already shared what i am up to. did you read the comments of the code i shared? my goal with this and my aporoach, and the problems I am facing. you can read it there.
btw, I found a better approach.
def dprn(*args, sep="\n"):
if not type(sep) is str:
raise TypeError(f"The optional keyward arg "
f"sep must be a string, {type(sep)} "
f"given.")
varn = [f"und{i}" for i in range(len(args))]
il = inspect.currentframe().f_back.f_locals.items()
for i, arg in enumerate(args):
for n, v in il:
if v == arg:
varn[i] = n
lvnl = len(sorted(varn, key=lambda x: len(x),
reverse=True)[0])
for a, b in zip(varn, args):
print(f"{a}:{' '*(lvnl-len(a))} {b}", end=sep)
i am still testing the possible shortcommings, for now i found that if for example do like
xx, yy, zz = 11, 12, 11
dprn(xx, yy, zz)
then the detection logic falters. i need a different aproach for detection logic.
I did read your comments, but they don’t answer the “why” question I asked, at all. You seem committed to this unusual course, though, so I will just wish you good luck.
Change your api to pass in the required context would be one solution.
Maybe that is the module of the caller. Maybe an instance of a class to hold the data?
I guess that the data is such that you cannot avoid using eval?
why people make frankenstine? because they can. “what if i do this” is the root of every reason for anything. and for me beside this while debugging scripts i tend to use print function a lot, but then sometimes values needs to be named to understand whats doing what. and i am a lazy person, so writing those names=value sometimes becomes frastrating. so i wanted a solution. hope this is enough for you.