I have written a package with the 'standard' minimal structure. It looks like this:
my_package/
my_package/
__init__.py
setup.py
__init__.py
contains a class and as such can simply be imported and used as one would expect.
However, the code really lends itself to be used in a command-line-way, e.g.
python my_package --arg1 "I like bananas."
At first, I just had an if __name__ == '__main__'
check in __init__
which would then use argparse
. This works but it isn't pretty, because it would mean that you'd call it from the command line like so:
python my_package/__init__.py --arg1 "I like bananas."
From what I read, this is where a __main__.py
file comes in which would be executed as the default script inside a folder (similar to a index.html
file on a website). The idea I have is to then simply import __init__.py
, run argparse and feed the arguments to the class constructor. Like so:
import argparse
from __init__ import MyClass
parser = argparse.ArgumentParser()
parser.add_argument("--arg1", help="Some dummy value")
args = parser.parse_args()
my_class = MyClass(**vars(args))
my_class.do_stuff()
Is this how similar packages ought to be structured, or is there a better way?
The above works but PyCharm tells me that in __main__.py
__init__
is an unresolved reference. Same for MyClass
on that import line. When I use .__init__
instead (with a dot) the warning goes away but then the code doesn't work anymore, giving me a ImportError: attempted relative import with no known parent package
.
To run Python scripts with the python command, you need to open a command-line and type in the word python , or python3 if you have both versions, followed by the path to your script, just like this: $ python3 hello.py Hello World!
Command-line applications, also referred to as Console Applications, are computer programs designed to be used from a text interface, such as a shell.
You can use any directory name, such as /home (in Linux), C:/folderName (in Windows), and so on. You can use the dot if you want the package to be in the same directory ( . ) The current working directory is represented by the dot "." operator. Look at my H: the above command built the mypackage (folder) successfully.
Command Line Scripts¶. Many Python packages include command line tools. This is useful for distributing support tools which are associated with a library, or just taking advantage of the setuptools / PyPI infrastructure to distribute a command line tool that happens to use Python. For funniest, we’ll add a funniest-joke command line tool.
Run below steps to compile and run java programs from command line: “javac” is the java compiler available in bin folder of the jdk. “ -d ” stands for the “ directory “. it explains compiler that where the class files should be created.
After the program has been compiled, run it using the command. Recognize the following command. java:- It is the Java application launcher. mypackage:- It is our package name.
I want to suggest a different structure to you:
my_package/
my_package/
__init__.py
cli_scripts.py
setup.py
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__
):
class Test(object):
def __init__(self, a)
self.a = a
def __call__(self):
print(self.a)
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
:
import argparse
from my_package import Test
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("a", type=int, help="Just an example argument")
return parser.parse_args()
def demonstration():
args = parse_args()
t = Test(a=args.a)
t()
My suggestion now is to utilize the console_scripts entry point inside setup.py
, which could now look something like this:
from setuptools import setup
setup(
name='testpy',
version='0.1',
description='Just an example',
author='RunOrVeith',
author_email='[email protected]',
packages=["my_package"],
entry_points={
"console_scripts": ["mypkg=my_package.cli_scripts:demonstration"]},
install_requires=[],
)
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()
.
This way:
__main__
filespython
entry_points
__main__
I think this is pretty clean.
You can read more about entry_points
in this blog, it has more functionalities!
If you want to use code specified in __main__
instead of this cli_scripts
approach, you can have a look at this question.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With