I'm trying to create a cli tool using python but whenever I try to run the command in terminal i get the error 'bash: command not found'. The python modules installs without any errors. I'm on macos and using python version: 3.9.4. I think this may be a PATH issue but currently unsure.
Here is the setup.py:
from setuptools import setup
setup(
name = 'mycommand',
version = '0.1.0',
packages = ['mycommand'],
entry_points = {
'console_scripts': [
'mycommand = mycommand.__main__:main'
]
}
)
Here is the main.py:
import sys
def main():
print('in main')
args = sys.argv[1:]
print('count of args :: {}'.format(len(args)))
for arg in args:
print('passed argument :: {}'.format(arg))
if __name__ == '__main__':
main()
Hope somebody can help me with this.
This is the tutorial I have followed: https://trstringer.com/easy-and-nice-python-cli/
if your layout is like that:
setup.py
mycommand/main.py
then the entrypoint is simply mycommand.main:main:
mycommand/main.py -> mycommand.main
:main -> def main()
You need to use the scripts keyword argument.
First add a file called mycommand (note that you should not have any extension) in the same directory as main.py
#!/usr/bin/env python
from mycommand.main import main
main()
then edit your setup.py like this:
from setuptools import setup
setup(
name = 'mycommand',
version = '0.1.0',
packages = ['mycommand'],
scripts=['mycommand/mycommand'],
)
Then when you install this package you will be able to call mycommand
Related
How can I execute python function from a package without main / pip install in editable mode
e.g.
my sample.py is
def cli():
print("I'm running myTest")
return 0
and setup.py as
setup(
name="sample",
version="1.0",
py_modules=["sample"],
include_package_data=True,
entry_points="""
[console_scripts]
sample=sample:cli
""",
)
now if I do pip install -e . and execute sample
I get desired o/p as
I'm running myTest
However with this I'm not able to debug it,
What's ideal way to execute function from a module without pip install / using another python file,
also tried with python -m sample but that gives no o/p since there is no entrypoint
So call your function in your sample.py:
def cli():
print("I'm running myTest")
return 0
if __name__ == "__main__":
cli()
Then, from the command line:
python sample.py
See here for what if __name__ == "__main__": means:
https://www.freecodecamp.org/news/if-name-main-python-example/
If you want to leave sample.py completely unmodified, then you just create a new file test_sample.py and import sample to use it like so:
import sample
sample.cli()
or, as an alternative method of import, test_sample.py can also be:
from sample import cli
cli()
Then you run:
python test_sample.py
Just make sure test_sample.py is in the same directory as sample.py.
I have a module sfind.py. How can I do this so that I can run the script by the file name without the py prefix?
python sfind instead python sfind.py
sfind.py
import argparse
def createParser():
some logic
return parser
def main(namespace):
some logic
if __name__ == '__main__':
parser = createParser()
namespace = parser.parse_args()
main(namespace)
I tried to do it with setuptools, maked new file setup.py in same directory.
setup.py
from setuptools import setup
setup(
name='sfind',
version='0.1',
packages=['sfind'],
entry_points={
'console_scripts': [
'sfind=sfind:__main__'
]
})
But error occurred
python: can't open file 'sfind': [Errno 2] No such file or directory
Can anybody help me do it right?
File structure:
-sfind
--__init__.py
--__main__.py
--sfind.py
--test.py
You don't need setuptools to call your module as python sfind. Setuptools will allow you to call by just sfind. To call it with python sfind, you have to make your sfind a module and you can do this by making a python directory sfind with __init__.py, __main__.py, and sfind.py in the directory. Then, you can call with just python sfind. If you just want to call it with sfind, you can use setup tools, but it is recommended you provide callable function (e.g. sfind=sfind.sfind:main) instead of module itself (__main__) as your entry_points. You can then do either python setup.py install or python setup.py sdist then pip install.
I try to make a executable *.egg file. I can create this using the following method: I just put a __main__.py at the top-level of an .egg named .zip, and python will run that __main__.py
I have read that there is a more elegant way:
setup(
# other arguments here...
entry_points={
'setuptools.installation': [
'eggsecutable = my_package.some_module:main_func',
]
}
)
https://setuptools.readthedocs.io/en/latest/setuptools.html#eggsecutable-scripts
But if I create ( with run setup.py bdist_egg) and run the *.egg, it prints:
C:\Python27\python.exe: can't find '__main__' module in <eggpath>
So python doesn't find the entry point.
Is it possible make an executable egg without explicit __main__.py?
System:
Win 7
Python 2.7.9
setuptools 39.0.1 from c:\python27\lib\site-packages (Python 2.7))
UPDATE
I have tried both on Linux both with python3 and I got the same error.
It seems like the entry points documentation is misleading and you don't need them.
What you probably want something like this:
setup.py:
import setuptools
setuptools.setup(
name="example_pkg",
version="0.0.1",
# all the other parameters
# function to call on $ python my.egg
py_modules=['example_pkg.stuff:main']
)
example_pkg/stuff.py
def main():
print("egg test")
if __name__ == '__main__':
main()
create the egg: setup.py bdist_egg
run the egg: python dist\example_pkg-0.0.1-py3.6.egg
output: egg test
solution source: https://mail.python.org/pipermail/distutils-sig/2015-June/026524.html
I have written a Twisted bin file that is deployed on /usr/bin during application deployement, based on the Axiom example provided elsewhere on StackOverflow (I don't remember where), the project can be found here.
My problem is that, during the python setup.py install process, the installed bin file is different than the one from Axiom package:
/usr/bin/axiomatic
#!/code/venv/bin/python
from axiom.scripts import axiomatic
axiomatic.main()
/usr/bin/myapp
#!/code/venv/bin/python
# EASY-INSTALL-DEV-SCRIPT: 'MyApp==0.0.1','myapp'
__requires__ = 'MyApp==0.0.1'
__import__('pkg_resources').require('MyApp==0.0.1')
exec(compile(open(__file__).read(), __file__, 'exec'))
and the latter doesn't work when invoking it from the bash shell: myapp start
I get the following error: unknow command myapp
If I use python setup.py develop instead of python setup.py install everything works smoothly.
I have setup a little test application that starts a tcp service on port 1234:
the command twistd finger works, the service starts
the command fingerize start (different name on purpose, to be sure not calling the wrong one) doesn't work
Here is the code:
bin/fingerize
#!/usr/bin/python
from finger import tap
tap.main()
twisted/plugins/finger_plugin.py
from twisted.application.service import ServiceMaker
Finger = ServiceMaker('Finger', 'finger.plugins', 'blah', 'finger')
finger/plugins.py
from twisted.application import internet
from twisted.internet import endpoints
from twisted.python import usage
from twisted.internet import protocol
class Options(usage.Options):
""" """
def makeService(options):
from twisted.internet import reactor
endpoint = endpoints.TCP4ServerEndpoint(reactor, 1234)
return internet.StreamServerEndpointService(
endpoint,
protocol.Factory())
finger/tap.py
import sys
from twisted.python import usage
from twisted.scripts import twistd
class Start(twistd.ServerOptions):
run = staticmethod(twistd.run)
def subCommands(self):
raise AttributeError()
subCommands = property(subCommands)
def parseOptions(self, args):
print(sys.argv)
print(args)
a = self.getArguments(args)
print(a)
sys.argv[1:] = a
print(sys.argv)
print('Starting finger service...')
self.run()
def getArguments(self, args):
args.extend(['--pidfile', self.parent.pid()])
args.extend(['finger'])
return args
class Options(usage.Options):
def subCommands():
def get(self):
yield ('start', None, Start, 'Launch finger service')
return get,
subCommands = property(*subCommands())
def pid(self):
return '/tmp/finger.pid'
def main(argv=None):
o = Options()
try:
o.parseOptions(argv)
except usage.UsageError, e:
raise SystemExit(str(e))
setup.py
from setuptools import find_packages
from setuptools import setup
METADATA = dict(
name='Finger',
version='0.0.1',
packages=find_packages(),
scripts=['bin/fingerize'],
install_requires=[
'Twisted >= 15.5.0',
],
include_package_data=True,
zip_safe=False,
)
setup(**METADATA)
And when I call fingerize start I get: /code/test/bin/fingerize: Unknown command: finger (test is a virtualenv)
Since you are using setuptools in your setup.py, you can use the newer entry_points keyword, like so:
entry_points={
'console_scripts': [
'fingerize=finger.tap:main',
],
},
instead of the scripts keyword.
Note if python setup.py install is run in a virtualenv, it will put the script in env/bin/fingerize (assuming your virtualenv folder is env).
A nice way to make such "python applications" then available globally (for some deployment purpose), while their inner mechanics doesn't interfere with your system python applciations, is to use pipsi (pip install pipsi) (made by the guy who developed flask). It's designed to expose just the project's executables to the system and have everything else tucked away in its own virtualenv.
You can see more on how to write/configure/distribute python packages at the packaging.python.org guide.
I am trying to learn about entry_points and how to use Python from the command line. My OS is Linux (Mint 15), and I tried unsuccessfully with both Python 2.7.4 and 3.3.1 -- with virtualenv.
foo/setup.py:
setup(
name='foo',
version='0.0.1',
description='foo',
url='http://www....',
author='Foo',
author_email='xxx#xxx.com',
install_requires = ['docopt', 'termcolor'],
packages = ['foo'],
entry_points = {
'console_script': [
'foo = foo.main:start'
],
},
)
foo\foo\main.py:
def start():
print 'test'
foo\foo\__init.py__: empty
I installed with: python setup.py develop
(learn27)user#machine /data/apps/learn27/rocks $ python setup.py develop
running develop
... more output here
But when trying to run "foo" from the command line, it simply says "command not found". I could not find any file named "foo" onthe file system.
As far as I understand, I was expecting the generated executables to be located in the bin folder here:
>>> print distutils.sysconfig.get_config_var('prefix')
/data/apps/virtenvs/learn27
Thanks in advance for any help!
The entry point is called console_scripts, plural, you misspelled it as console_script (singular).
See Automatic Script Creation in the setuptools documentation.
You may have to add it to your PATH