4

I am trying to get a single Python file as a output. I have a Python script that has several imports of the kind:

from that import sub

The imports are from all local modules and nothing from the system or Python libraries. Is there any way to resolve those and get a single complete code file? That is, can I include all the method/function definitions into final file?

I can do this manually, but there are many imports. Is there already some way to do this?

My Python version is 2.4.3.

David Cain
  • 16,484
  • 14
  • 65
  • 75
mtk
  • 13,221
  • 16
  • 72
  • 112
  • like `from that import *`? – thefourtheye Jan 16 '14 at 13:38
  • 2
    @thefourtheye: The OP wants an automated module merge; anything the main module uses should instead be moved to the main module source file. – Martijn Pieters Jan 16 '14 at 13:39
  • If all your imports are of the form `from modulename import name` then you can simply copy and past *all* of `modulename` into the main script. I'm not aware of any automated tools, but it is certainly *possible* to automate this task. Not sure you'd want to do this, but it's your funeral. – Martijn Pieters Jan 16 '14 at 13:40
  • @Martijn yup that is a solution but i have several different module part being imported – mtk Jan 16 '14 at 13:41
  • possible duplicate of [Combining module files in Python](http://stackoverflow.com/questions/1104066/combining-module-files-in-python) – jonrsharpe Jan 16 '14 at 13:49
  • Is Python 2.4 really a requirement?? – Henry Keiter Jan 16 '14 at 14:43

5 Answers5

7

It seems, that most of the people who answers did not get the question correctly (I hope, I did). The question is not about "how to avoid having multiple imports"... It's about: "how to get single python script from multiple python modules?"

I have the same question. And the use case is following:

I develop some extension for some system with web-based GUI. The extensions are written in python. The systems itself exposes some of its facilities through its python API. But due to restrictions of the system it can only work with single-file modules. I.e. I have to keep all my code in one file. On the other hand the scripts tend to become quite complicated (thousands of lines) and also it is desirable to re-use some common functions (logging, error handling etc.) with some mechanism, which is more intelligent, than copy-paste.

What comes to mind is to do development normally with modules. And then use some "builder", which would take all the modules used in particular end-use script and combine them together into single file.

And now the question is: Does such a "builder" exists?

Note, that use of py2exe is not an option, as I need python source file as an output.


The only ready made solution, which I found was given in the discussion already mentioned by jonrsharpe above here.

It is Breeder tool. Being honest, I did not try it, but according to description it is supposed to do what is required.

As of me, I decided to develop my own tool, which handles some special points (as printing out correct line numbers in the exception traps etc.). But it is still work in progress, so I cannot share it now.

Community
  • 1
  • 1
Dmitrii Semikin
  • 2,134
  • 2
  • 20
  • 25
  • Five years later, I have this same question. I am wondering if the [ast](https://docs.python.org/3/library/ast.html) package can be used to accomplish this – Matthew Leingang Jul 03 '20 at 12:52
1

If you want to include all the imports in a single file you can try appending the paths.

import sys
sys.path.insert(0,'path/to/your/folder/containing/file/to/be/imported')
import your_module
Ashoka Lella
  • 6,631
  • 1
  • 30
  • 39
0

You can move all your modules to one directory and then do from thatdir import *. Then every time you want to add any module to this directory, you will just have to edit the __init__.py to include that module. See below directory structure for this, script and execution

# Putting All my modules in `MyModule` directory

[root@Machine python]# cd MyModule/
[root@Machine MyModule]# pwd
/python/MyModule
[root@Machine MyModule]# ls -l
total 32
-rw-r--r--. 1 root root  46 Jan 16 06:35 __init__.py
-rw-r--r--. 1 root root 178 Jan 16 06:36 __init__.pyc
-rw-r--r--. 1 root root  48 Jan 16 06:36 ModuleA.py
-rw-r--r--. 1 root root 267 Jan 16 06:37 ModuleA.pyc
-rw-r--r--. 1 root root  42 Jan 16 06:36 ModuleB.py
-rw-r--r--. 1 root root 261 Jan 16 06:37 ModuleB.pyc
-rw-r--r--. 1 root root  44 Jan 16 06:37 ModuleC.py
-rw-r--r--. 1 root root 263 Jan 16 06:37 ModuleC.pyc

# Including modules to be imported by * import in __init__.py

[root@Machine MyModule]# cat __init__.py
__all__ = [ "ModuleA", "ModuleB", "ModuleC" ]
[root@Machine MyModule]#

# Sample Script showing import of these modules in one statement 
[root@Machine MyModule]# cd ..
[root@Machine python]# cat myscript.py
from MyModule import *

ModuleA.printHello()
ModuleB.printHi()
ModuleC.printHey()

# Execution of script
[root@Machine python]# python myscript.py
Hello from Module A
Hi from Module B
Hey from Module C
[root@Machine python]#

This way you dont have to create a new file with all functions and you get only one import statement too.

0

I don't believe there's a built-in way to do this. I actually wrote a (very naive) tool to do some of this work automatically, but only because I actually need to do this (create single-file Python scripts) relatively often for work. That tool isn't particularly portable itself, though; it has a lot of finicky bits, makes a bunch of requirements of the source, and it's certainly not compatible with Python 2.4.

If you're only going to be doing it once, you'll find it a heck of a lot easier to just copy in the non-core source modules by hand.

Alternately, if staying cross-platform isn't a requirement, you could look into pyinstaller, which makes executable binaries out of Python code. That could get everything into one file without requiring a lot of source-code manipulation on your part.

Henry Keiter
  • 16,863
  • 7
  • 51
  • 80
0

Here is a very short module-inliner script that pastes imports of the form from ... import * recursively into file given in argv[1] and writes everything out to argv[2]:

import os, sys, re

if len(sys.argv) < 3:
    print ( "usage:", sys.argv[0], "[input file] [output file]" )
    exit()
print ("input:", sys.argv [1], "output:", sys.argv[2])

excludes = ["browser"]

def process_file ( filename ):
  global excludes
  src = open ( filename, "r" ).read ()
  str = "from (\w+) import (.+)\n"
  imp = re.findall (str, src )
  for a, b in [(a, b) for a, b in imp if a not in excludes]:
    print ("import:", a, "file:", filename, "...")
    paste = process_file ( a + ".py" )
    src = src.replace ( str.replace ( "(\\w+)", a ).replace ( "(.+)", b ), paste )

  #print (imp)
  print ("concatenated file:", filename, "size:", len (src) )
  return src

open ( sys.argv [2], "w" ).write ( process_file ( sys.argv [1] ) )

I wrote this for use with Brython (https://brython.info/). If you import more Brython modules than just browser you have to extend the global variable excludes. Because trying to inline these would fail. As main input either a *.py or a *.html file can be passed.

areop-enap
  • 396
  • 1
  • 7