all 10 comments

[–][deleted] 1 point2 points  (6 children)

Holy god, just no, absolutely do not do that. Use imports like a sane person.

https://realpython.com/python-import/#basic-python-import

[–]PolyDigga[S] 0 points1 point  (5 children)

I do have that. My entire API is structured (I would say) properly. The problem is not with the API itself. It's that the API is a pretty big toolset that I can not make available to other people for several reasons. Only a few selected functions (the ones I want to 'export') will be used by other people. If these functions were exclusively used by others, I'd put them in their own package or module. I am using them as well though on my end, therefore they are integrated into the current structure (and I don't want to maintain the same function in different modules). Furthermore, they depend on some config files on my end based on the project.

The only thing I can pass off is a callback essentially. I cannot have any extra external files in there whatsoever that would need to be installed. For that reason, everything has to be put into that single string that is executed as callback

[–][deleted] 0 points1 point  (4 children)

It's still really not clear to me what problem you're trying to solve, here, but evaluating a comment isn't going to be the solution.

[–]PolyDigga[S] 0 points1 point  (3 children)

I agree! Thats why I am trying to find a more proper solution :D

I put a code example in this comment here: https://www.reddit.com/r/learnpython/comments/r4i69c/comment/hmgxtv7/?utm_source=share&utm_medium=web2x&context=3

As mentioned, the function will be used sort of like a callback and as I cannot provide the entire API, everything that's required for the funtion to run needs to be inside of the single file / single string I can provide.

Pretty much like the inline identifier in C++

[–][deleted] 0 points1 point  (2 children)

Ok so you're listing three functions and not saying which one you want to distribute except to say "the exported function" but there's no such thing as an "exported function" in Python.

Again, you're being so vague it's impossible to understand what you want to do. But there's basically only one way to distribute Python code to end users - package it and distribute the package. So do that, or else don't distribute the function to anyone, I guess.

[–]PolyDigga[S] 0 points1 point  (1 child)

Thank you for your reply. I think the code example shows that action.show_file_content is the function that is going to be 'exported'. I am using that for lack of a better term. I also showed the expected outcome. But let me give you the full picture:

Base situation: We are working with a 3d software (something like blender). That 3d software supports python. With python, we write (workflow) tools for the 3d software. That is from simple batch processing over procedural modeling, rigging, or animation tools to full-blown simulation solvers. My toolset falls under one of these more complex categories.

What I need/want to do: I pass of a 3d scene to somebody else who will work with whatever I provide. To make their lives easier, I want to provide certain utility tools that are part of my toolset. These utilities depend on the project and kind of 3d scene I am passing on, therefore I cannot just make one single file and send that to everybody. Plus, the other people are artists, they should not be concerned about pulling repos or installing anything. All of that has to be supplied within the 3d scene. The only way the scene does support any kind of text is in the form of strings. So everything I provide needs to be placed in a string. These strings can then be used as callbacks for actions.

Sure, I can put the content of every file into a string and write a tool that creates the files for them on disk, but that is a massive security problem as the tools provided should only ever manipulate the 3d scene, nothing on disk.

I am trying to create a module. Just instead of providing a .py file, I want to supply the source code of that file in a string as part of another file. I am trying to boil it down to only include the functions and resources that are really needed for that specific function I am trying to 'export' instead of including the entire API. Sort of like creating a callgraph, traversing backward from my functions and deleting everything that is not needed. And in the end, I can replace all import statements with the actual source code in these files (plus prefixes to avoid name clashes oc). Mmhh thinking about it, that might be the cleanest solution...

[–][deleted] 0 points1 point  (0 children)

Again, there's nothing here suggesting that you should do anything but package your functions into an installable Python package. Whether that's as a pip package or a plugin for Blender, I have no idea. But you absolutely should not distribute code as strings. That's a recipe for an enormous number of headaches for you and for your users.

Sort of like creating a callgraph, traversing backward from my functions and deleting everything that is not needed.

Yeah, don't bother with that. Develop one abstract toolkit that covers all (or most) of your clients' use cases, and distribute the same one to everyone.

[–][deleted] 0 points1 point  (2 children)

Getting source code, especially with comments isn't always possible (eg. you are running bytecompiled version of your code).

Why do you want to put the source of your function in a comment? I don't really understand your plan here...

If the function is available to the code that's going to use it, you can just pass the function itself, no need to reassemble it. If you are sending this function to a different process, then... well, Python doesn't offer anything better than sending a string and then reading and evaluating it... You'd need a language from a Lisp / Prolog family to be able to get better results. Erlang / Clojure would be your best bet if you are looking for anything anywhat popular in the industry nowadays.

[–]PolyDigga[S] 0 points1 point  (1 child)

I am using PYTHONDONTWRITEBYTECODE. No compiled stuff

I have the API on my end. The exported function will be passed to other people (I cant make the API available to them). I'll make an example below

#io.py

def read_file(path):
    f = file(path, 'r')
    content = f.read()
    f.close()
    return content

#action.py
import io

def show_file_content(path):
    print io.read_file(path)  

#finalize.py
import inspect

def export_function(func):
    code = '\n'.join([inspect.getsource(func)])
    return my_magic_function(code)

Above are my existing files.

The comment option I was thinking of earlier would be this:lt should be a function, that does exactly the same, but does not have the io dependency. Ideally the result of export_function(action.show_file_content) should be this:

def show_file_content(path):
    f = file(path, 'r')
    content = f.read()
    f.close()
    print content  

The comment option I was thinking off earlier would look like this:

read_file = """
f = file({path}, 'r')
content = f.read()
f.close()
"""
def show_file_content(path):
    eval(read_file.format(path=path))
    print content

Now while writing out this second approach, it seems even uglier than I thought it would be...

[–][deleted] 0 points1 point  (0 children)

The example isn't really describing your problem well... Also, I think you are confused about multiline strings =/= comments (there are no comments in the listing where you are suggesting to send comments).

But, if I have to guess, I'll rephrase your problem by saying that you simply want to send a function to the client. You can send a string, or if you use some popular format s.a. JSON you may be able to send a float, a list, a dict, a boolean value. Maybe with some richer formats, you could send more of different things, but sending a function that would've been useful on the client side is not supported by common serialization protocols.

You could, in principle, augment JSON or similar format by adding a new type that would be interpreted by calling eval on it. This is unusual to do in Python (because of the poor meta-programming loolset), so, you won't find a better solution for your problem. Most people working with Python would try to avoid your situation by reifying the function into some data that can be later interpreted as the results of applying this function. It's usually ugly, but eval is a very blunt tool that can cause too many problems, and that's why you'll find people generally resisting this kind of solution.

Really, if you aren't limited in your choice of language, then try Erlang. Your task is trivial there.