Reputation: 53
I am working on a Python project and started using a setup.py file to install it. I followed some guides on how to structure the project and everything is working great after installing it.
My problem is that I "lost" the ability to run my application from inside the project's directory, locally so to speak without installing it, for testing purposes. Here's how the directory layout looks like:
project_dir/
├── bin
│ └── app.py
├── data
│ └── data.conf
├── app_module
│ └── __init__.py
├── LICENSE
├── README.md
└── setup.py
The problem has to do with the imports. In app.py
I have import app_module
and it works as intended after it gets installed to the proper directory by running python setup.py install
. If I want to run it by doing python bin/app.py
it obviously doesn't work.
What am I doing wrong and how could I get this to work? Ideally I want to be able to run it from inside the directory and it should still work when installed with the setup.py
script.
Upvotes: 0
Views: 61
Reputation: 3420
if your bin/app.py
is only doing:
import app_module
app_module.run() # or whatever you called the main() function
you could (should!) use an entry_points
(search for console_scripts
).
And while running your uninstalled code, you would do either:
python -m app_module
or python app_module/__init__.py
(assuming you have a __main__
section inside this file, otherwise look at how json.tool
is doing.
Here is a basic example, assuming your library is named "app_module".
import imp
import os
import setuptools
module_name = 'app_module'
module = imp.load_module(
module_name,
*imp.find_module(module_name, [os.path.dirname(__file__)])
)
base = 'data'
data_files = [
(
'/usr/local/share/appdata/' + module_name + root[len(base):],
[os.path.join(root, f) for f in files]
) for root, dirs, files in os.walk(base)
]
setuptools.setup(
name=module_name,
version=module.__version__,
classifiers=(
'Environment :: Console',
'Operating System :: POSIX :: Linux',
),
packages=(
module_name,
),
entry_points={
# the executable will be called 'app' (not 'app.py')
'console_scripts': ['app = ' + module_name + ':main'],
# it does not seems unnecessarily complicated to me, it's just three lines
},
data_files=data_files,
)
import optparse
import sys
__version__ = '1.2.3'
def main():
parser = optparse.OptionParser(version=__version__)
parser.add_option('-m', '--man', action='store_true')
opt, args = parser.parse_args()
if opt.man:
help(__name__)
sys.exit()
print opt, args
if __name__ == '__main__':
main()
To run it:
python /full-or-replative/path/to/app_module/__init__.py
# or
export PYTHONPATH=/full-or-replative/path/to/app_module/
python -m app_module
To install and run it:
# test in a virtualenv
workon test
python setup.py install
app -h
Upvotes: 1
Reputation: 14401
What you need to do is either set the python path to include your module (ie run it as PYTHONPATH=project_dir python app.py
, or make the app_module
be placed in project_dir/bin
in order to be included in the builtin path.
Note that not doing this is dangerous as after installed your app.py
would otherwise pick up the installed package (app_module
) instead of that in your project dir (which can get confusing).
Upvotes: 0