Skip to content

Commit dc269a0

Browse files
authored
Update python-packaging.md
1 parent 18ef5a3 commit dc269a0

File tree

1 file changed

+68
-0
lines changed

1 file changed

+68
-0
lines changed

python/python-packaging.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,71 @@ setup(
3636
setup_requires=["setuptools>=62.1.0"],
3737
)
3838
```
39+
40+
## Structure of package with CLI scripts
41+
42+
Example structure:
43+
44+
```
45+
my_package/
46+
my_package/
47+
__init__.py
48+
cli_scripts.py
49+
setup.py
50+
```
51+
52+
Let's assume your `__init__.py` looks like this (as a side note, I'd recommend moving the classes defined in there to a separate file, and then simply importing that file in the `__init__`):
53+
54+
```python
55+
class Test(object):
56+
57+
def __init__(self, a)
58+
self.a = a
59+
60+
def __call__(self):
61+
print(self.a)
62+
```
63+
64+
Now there is an additional file inside the package that utilizes the stuff you implemented in the package, let's call it `cli_scripts.py`:
65+
66+
```python
67+
import argparse
68+
69+
from my_package import Test
70+
71+
def parse_args():
72+
parser = argparse.ArgumentParser()
73+
parser.add_argument("a", type=int, help="Just an example argument")
74+
return parser.parse_args()
75+
76+
def demonstration():
77+
args = parse_args()
78+
t = Test(a=args.a)
79+
t()
80+
```
81+
My suggestion now is to utilize the `console_scripts` entry point inside `setup.py`, which could now look something like this:
82+
83+
```python
84+
from setuptools import setup
85+
86+
setup(
87+
name='testpy',
88+
version='0.1',
89+
description='Just an example',
90+
author='RunOrVeith',
91+
author_email='xyz@mailinator.com',
92+
packages=["my_package"],
93+
entry_points={
94+
"console_scripts": ["mypkg=my_package.cli_scripts:demonstration"]},
95+
install_requires=[],
96+
)
97+
```
98+
Now when you run `pip install .` inside the top-level `my_package` folder, your package will be installed. The `entry_points` automatically generate an executable for you, that you can now call with the name you gave it inside `setup.py`, in this example `mypkg`. This means you can now run `mypkg 5` and this will call `demonstration()`.
99+
100+
This way:
101+
102+
- you do not need to handle any `__main__` files
103+
- you can give your script a meaningful name
104+
- you don't need to care whether your script is executable, or specify to run the script with python
105+
- you can have as many of these as you want inside the list `entry_points`
106+
- it forces you to write functions that you could also call from other modules, instead of the `__main__`

0 commit comments

Comments
 (0)