Reputation: 890
I've been coding in Python for long, but never actually tried to pack a piece of code so that I can share it. I started reading https://python-packaging.readthedocs.io/en/latest/.
I started with the simplest possible case, say I want to share a module named 'clipper', and the only important thing is a class called Clipper. It seems in case I use setuptools I should create somewhere folders
clipper/clipper
and inside the inner clipper, place a file __init__.py
with the definition of class Clipper. So far so good. Theoretically, after installing the package, the way to use the class would be:
import clipper
cl = clipper.Clipper()
My problem is, I am assuming that while I am developing and before any installation, the same code should work. I mean, the previous code should create an instance of the object. But how would that work? How should I set PYTHONPATH so that the previous import would actually work?
Maybe I got something really wrong, I thought packing would be easier compared to coding, but I've spent some time and I don't get it. Any help, please?
Upvotes: 0
Views: 98
Reputation: 777
Your directory tree would look a bit like this:
~/clipper/
setup.py
clipper/
__init__.py
clipper.py
The setup.py
file contains information telling Python how to 'parse' your package. Things like the name of your project, the version and what packages to include are defined here. For your example, setup.py
may look like this:
from distutils.core import setup
setup(
name="Clipper",
# A name for your package, typically your project name
description="My first package",
# A short description
version="1.0.0",
# A version specification
packages=["clipper"]
# A list of packages to include
)
Within clipper
, clipper.py
contains the actual Clipper
class:
class Clipper(object):
def __init__(self):
pass
def foo(self):
print("Invoked foo!")
__init__.py
is a special type of file. It defines the public interface for interacting with your package. Typically, it import
s all public functions and classes:
from .clipper import Clipper
Finally, to turn this into a proper package, run python3 setup.py sdist
. This creates the source distribution for your package and allows you to import it 1. Let's try that now. Navigate back to ~/clipper/
and start Python:
>>> from clipper import Clipper
>>> c = Clipper()
>>> c.foo()
Invoked foo!
>>>
And here's 'real' example of what a package directory would look like:
~/calculator/
setup.py
calculator/
__init__.py
add.py
substract.py
setup.py
from distutils.core import setup
setup(
name="Calculator",
description="Calculate stuff!",
version="1.0.0",
packages=["calculator"]
)
__init__.py
from .add import *
from .substract import *
add.py
def add(a, b):
"""Return `a` + `b`."""
return a + b
substract.py
def substract(a, b):
"""Return `a` - `b`."""
return a - b
For more information, see the Python tutorial on packaging.
1 You may get some warnings about missing information, but you can ignore that for now.
Upvotes: 1
Reputation: 2162
Rather than modifying your Python path, install the packaged module as an editable version and your environment will handle this for you. When you have it running as an editable version you'll be able to make changes to the code on your local development instance.
For example, assuming you have Pip you can run the following command in the first 'clipper' folder (the same folder as the setup.py
file you created during packaging):
pip install -e .
-e
means editable.
means install the package located in the current folder. More detail here in an SO answer from 2015: "pip install --editable ./" vs "python setup.py develop"
Upvotes: 2