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