Export python module (to string or py file)

Summary: I want to take a variable of type 'module' and export it.

I am importing a python module from a .py file using import and making changes to it. I need to export the module back to a file or get a string representation of the complete module, which can then be written to disk.

I could not find any way to export the python module or a way to convert the objects in the module into strings in a structured, plain text python-executable format. (not json, etching, etc.)

Detailed question and usage: This requirement is part of the internal assembly process; There are no security requirements, and only our own modules, not the built-in modules, are changed. The Python script works with business logic to modify a number of other scripts. This process uses information available only at build time. As a result, I have no way to import a module with various data at runtime.

The original system used a template with placeholder strings that would be replaced, but current requirements require more complex modifications to declare objects, where programmatically changing an object is much easier than replacing strings.

What I did Using the main script generator written in python, I can import several modules (which have only variable declarations and no executable code) and make all the necessary replacements. I am left with a variable of the type of the module, which I need to export back to the file in order to subsequently be executed.

@Abarnert had good ideas. I did not know about the function of representation. This gave me information, but without formatting. It made me look at a pprint that is as close as I have come to what I would prefer.

Example example.py

sample = { 'level1_dict_1' : { 'key1' : 'value1', 'key2' : { 'level2_dict' : { 'key1' : 'value3', 'key2' : ['list1','list2','list3','list4'], } } }, 'level1_dict_2' : { 'key1' : 'value1', 'key2' : 'value2', }, } 

Very simplistic (and without any business logic) I basically want to do the following:

 with open("example.py","w") as outfile: example = __import__('example') # Import module example.sample['level1_dict_1']['key2']['level2_dict']['key2'][2] = "newlistitem3" # Change 1 property in a list nested a few levels deep outfile.write("sample = \n" + pprint.pformat(example.sample)) # 

I would like to have the same formatting as the source file, but pprint, being readable, has a different formatting than I would prefer. It can be as close as possible to what I need.

pprint output:

 sample = {'level1_dict_1': {'key1': 'value1', 'key2': {'level2_dict': {'key1': 'value3', 'key2': ['list1', 'list2', 'newlistitem3', 'list4']}}}, 'level1_dict_2': {'key1': 'value1', 'key2': 'value2'}} 

EDIT AND PERMISSIONS: - My goal is to load the module, modify it and save it as a python executable. It is for this reason that I object to pickle, json, etc. I need to create one py executable. - Revised use case for clarification - Added examples and additional information about what I tried

+4
source share
1 answer

What you ask for is impossible. You are trying to create source code from object code. Although there are decompiler projects that can do this to a greater or lesser extent, a completely general solution is not possible.

If you just want to get the source code of the module, this is easy. For example, you can use inspect.getsource , and then write the resulting string to a file. Or just use inspect.getfile and copy the resulting resulting path.

And you can, of course, change the original source when copying it. For instance:

 source = inspect.getsource(foo) with open('newfoo.py', 'wb') as f: f.write(source) f.write('spam = Spam(3)\neggs = Eggs(spam)\n') 

But you cannot change foo and then regenerate its source.


However, there are probably far better ways to do what you really need to do. For instance:

  • Use JSON, pickle (mode 0), YAML, etc. Despite what you claim, these are structured, readable text formats, just like the Python source.

  • Use repr . For string, numeric, and built-in literal constants, as well as lists and dicts containing only (recursively) the above types, repr is round. For instance:


 with open('newfoo.py', 'wb') as f: for name, value in foo.__dict__.items(): f.write('{} = {!r}\n'.format(name, value)) 
  • If you are sure that all your values ​​are workable but not positive, there are many ways to check or disinfect your product before recording it. For instance:

 with open('newfoo.py', 'wb') as f: for name, value in foo.__dict__.items(): if ast.literal_eval(repr(value)) != value: raise ValueError('Tried to save {}'.format(value)) f.write('{} = {!r}\n'.format(name, value)) 
  • Create data files in a good format that are perfect for your code generator, people readers, etc. instead of trying to generate a Python source and then write simple Python code that reads data files and generates objects at runtime.
+3
source

Source: https://habr.com/ru/post/1494866/


All Articles