Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: sharing common code among a family of scripts

I'm writing a family of Python scripts within a project; each script is within a subdirectory of the project, like so:

projectroot   |   |- subproject1   |    |   |    |- script1.main.py   |    `- script1.merger.py   |   |- subproject2   |    |   |    |- script2.main.py   |    |- script2.matcher.py   |    `- script2.merger.py   |   `- subproject3        |        |- script3.main.py        |- script3.converter.py        |- script3.matcher.py        `- script3.merger.py 

Now several of the scripts share some code. The shared code is best considered part of the project itself, and not something I would compile separately and make a library out of, or drop in a sitewide PYTHONPATH. I could place that code in various places, such as in the projectroot directory itself, or in a child directory of projectroot called common (perhaps).

However, most of the ways I have thought of so far involve making packages out of my subprojects with empty __init__.py files and using relative imports (or redundantly messing with sys.path in every subproject. Worse, it seems like building a package structure around this family of scripts runs afoul of the following warning from the rejected PEP-3122:

Attention! This PEP has been rejected. Guido views running scripts within a package as an anti-pattern.

If scripts within a package is anti-patternish, how can I set things up in a way which keeps the common code in the same project? Or is a module and package-based system acceptable here? Which is the cleanest approach? (FWIW I would prefer to have a file such as shared.py or common.py in the project root directory, rather than making a utility directory that is a sibling to the "real" subprojects.)

like image 928
Ray Toal Avatar asked Aug 06 '13 17:08

Ray Toal


People also ask

How do I share data between two python scripts?

Answer #1: you can use multiprocessing module to implement a Pipe between the two modules. Then you can start one of the modules as a Process and use the Pipe to communicate with it. The best part about using pipes is you can also pass python objects like dict,list through it.

Can two python scripts import each other?

As explained in my answer, it is possible for modules to import each other, but if you need to do that, you may want to reconsider your design.

Are python scripts cross platform?

Python is a cross-platform language: a Python program written on a Macintosh computer will run on a Linux system and vice versa. Python programs can run on a Windows computer, as long as the Windows machine has the Python interpreter installed (most other operating systems come with Python pre-installed).


2 Answers

I suggest putting trivial "launcher" scripts at the top level of your project, and making each of the subproject folders into packages. The modules in the packages can import each other or common code can be factored out into a common package.

Here's what the structure would look like, if we assume the various merger modules can be refactored into a shared version:

projectroot   |- script1.py # launcher scripts, see below for example code   |- script2.py   |- script3.py   |   |- common   |    |- __init__.py   |    |- merger.py # from other packages, use from ..common import merger to get this   |   |- subproject1   |    |- __init__.py # this can be empty   |    |- script1_main.py   |   |- subproject2   |    |- __init__.py   |    |- script2_main.py   |    |- script2_matcher.py   |   |- subproject3        |- __init__.py        |- script3_main.py        |- script3_converter.py        |- script3_matcher.py 

The launcher scripts can be very simple:

from subproject1 import script1_main  if __name__ == "__main__":     script1_main.main() 

That is, all it does is import the appropriate "scriptN_main" module and run a function in it. Using a simple script may also have some small benefits for script startup speed, since the main module can have its compiled bytecode cached to a .pyc file, while scripts are never cached.

Note: I renamed your modules, swapping _ characters in for the . characters. You can't have a . in an identifier (such as a module name), since Python expects it to indicate attribute access. That meant those modules could never be imported. (I'm guessing that this is an artifact of the example files only, not something that you have in your real code.)

like image 53
Blckknght Avatar answered Sep 20 '22 15:09

Blckknght


My preference would be a separate "bin" or "scripts" directory, with subprojects as libraries / packages:

projectroot   |   |- scripts   |   |- lib   |    |   |    `- matcher.py   |    `- merger.py   |    `- subproject1   |    `- subproject2   |    `- subproject3 

The idea being your scripts can each reference any subprojects necessary as usual packages. And your subprojects can also reference each other with imports.

You can then also have a main or shared script that sets up the subproject packages for you, if that helps.

like image 27
Matt S Avatar answered Sep 21 '22 15:09

Matt S