3

Recently I created a python script for PyPI. That you can download with pip install. The problem is you can only execute the script, that you downloaded with pip install, when you are in the Scripts folder which is where you python is localized (your_python_location/Scripts/myscript.py).
But this would be a hassle for the users. So I wanted to ask, how can I make it that you can execute the script from everywhere? (like you can do with pip without specifying the pip location). I also don't want that every user needs to set the path to the script.

My Setup.py (maybe its helpful):

import setuptools

with open("README.md", "r") as fh:
    long_description = fh.read()

with open('requirements.txt') as f:
    requirements = f.read().splitlines()

setuptools.setup(
    name="boston-housing-prediction",
    version="0.2.0a0",
    author="xx",
    author_email="xxx@gmail.com",
    py_modules=["misc_libary", "polynomial_regression_libary", "linear_regression_libary"],
    scripts=["boston-housing-main.py"],
    description="Predict housing prices in boston.",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/XXX",
    packages=setuptools.find_packages(),
    classifiers=[
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
        'Programming Language :: Python :: 3.5',
        'Programming Language :: Python :: 3.6',
        'Programming Language :: Python :: 3.7'
    ],
    keywords="regression meachine-learning housing_prices_boston learning_purpose",
    license="MIT",
    install_requires=requirements,
    python_requires='>=3.5',
)

Lupos
  • 896
  • 12
  • 40

2 Answers2

3

You can specify entry_points in setup.py, like

setuptools.setup(
    # ...
    entry_points = {
        'console_scripts': [
            'boston_housing = boston-housing-main:main'
        ]
    },
)

This will cause pip install to install a wrapper somewhere like /usr/local/bin/boston_housing which basically pulls in the module boston-housing-main and runs its main() function.

You probably want to replace the scripts entry with this, though there is no reason per se you could not have both.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • 1
    Maybe see also https://stackoverflow.com/questions/774824/explain-python-entry-points – tripleee Sep 22 '19 at 09:35
  • what is when I just want to execute the ````if __name__ == "__main__":```` without using a function like ````main````. Is that possible? – Lupos Sep 22 '19 at 09:43
  • 1
    The simple and obvious solution to that is to create a function `def main():` and then simplify to just `if __name__ == '__main__': main()`. It makes sense to keep the thing in the `if` as simple as possible for multiple other reasons, too. – tripleee Sep 22 '19 at 09:46
  • See also https://stackoverflow.com/a/69778466/874188 – tripleee Jan 16 '22 at 16:07
1

One approach to making a globally accessible Python script is to have your users call the module itself. If your package is called 'boston-housing-prediction', your users will be able to call your script from anywhere using the following command:

python -m boston-housing-prediction

What this does is calls a __main__.py file inside your package. This is just like any other Python script, so it can take arguments normally. All you have to do is rename your script to __main__.py and drop it into the package directory (not the folder including setup.py, rather into the folder including the package scripts), or create a new __main__.py that calls your script (you can just import the script if they are in the same folder).

The benefit of this approach is that it is platform independent, relying only on the proper installation of the packages. It doesn't rely on the OS at all.

anerisgreat
  • 342
  • 1
  • 7