Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Packaging a Python library with an executable

I just finished a module and want to package it. I've read the documentation and this question packaging a python application but I am not sure about how to proceed when I don't have a package to import but a script to launch instead.

The project looks like that:

Project/
|-- README
|-- requirement.txt
|-- driver.py
|-- run.py
|-- module_1
|   |-- __init__.py
|   |-- class_1.py
|   |-- class_2.py
|-- module 2
|-- |-- __init__.py
|-- |-- class_1.py
|-- |-- class_2.py

In order to launch the tool I do:

python run.py arg1 --option arg2

driver.py imports all other modules and defines a Driver class and some functions. run.py imports driver.py, parse arguments, setups the logger and calls the function one after the others to do the job.

I'm not sure about the configuration of setup.py, also do I need a global __init__.py at the root? From what I've understand, I will only be able to do import Project not to launch the script run.py with its arguments.

From other readings, maybe I should try to tell that Driver.py is the package and use the entry_points option of setup(). But I don't understand how to do all of it properly.

Thank you for your kind help!

like image 802
tupui Avatar asked Jul 15 '16 21:07

tupui


People also ask

Can a Python module contain executable code?

A module can contain executable statements as well as function definitions.

How do I make a package executable?

Choose the Create an Application Package>EXE Package task and then follow the wizard. Enter a package name. Select the executable file, e.g. a setup.exe. If you need additional files for the installation, select the option for packaging all files in the same directory and in the child directories.


1 Answers

Generally, you only distribute python packages as modules when the entire project fits in a single module file. If your project is more complex than that, it's usually best to structure your project as a package with an __init__.py file. Here is what your project would look like converted to a package

Project/
|-- README
|-- requirement.txt
|-- setup.py
|-- scripts/
|   |-- driver.py
|-- driver/
|   |-- __init__.py
|   |-- module_1
|   |   |-- __init__.py
|   |   |-- class_1.py
|   |   |-- class_2.py
|   |-- module_2
|   |-- |-- __init__.py
|   |-- |-- class_1.py
|   |-- |-- class_2.py

I renamed your run.py to scripts/driver.py and the code you previously had in driver.py is now driver/__init__.py.

Your setup.py should look like this

from setuptools import setup. find_packages

setup(
    name='driver',
    version='1.0',
    packages=find_packages(),
    scripts=['scripts/driver.py'],
)

This will copy scripts/driver.py to the python Scripts directory. I renamed run.py to driver.py since run is pretty generic and you want your script names to be unique since all python packages share the same scripts location.

Alternatively, you could use the console_scripts entry point. In this case, you wouldn't have a separate scripts/driver.py script. Instead, you would just have a function inside your package. In this case, you could move all the code from scripts/driver.py into driver/command_line.py and put it inside a function called main(). Then change your setup.py to this

setup(
    name='driver',
    version='1.0',
    packages=find_packages(),
    entry_points = {
        'console_scripts': ['driver=driver.command_line:main'],
    }
)

Also, you should read this docs page on python packaging. It covers the basics and a lot of the common use cases.

like image 155
Brendan Abel Avatar answered Sep 17 '22 16:09

Brendan Abel