pyinvoke / invoke

Pythonic task management & command execution.
http://pyinvoke.org
BSD 2-Clause "Simplified" License
4.36k stars 368 forks source link

Make invoke...zip executable #208

Open techtonik opened 9 years ago

techtonik commented 9 years ago

It will be handy for Gratipay to include invoke as an executable .zip file:

http://techtonik.rainforce.org/2015/01/shipping-python-tools-in-executable-zip.html

techtonik commented 9 years ago

I tried to send a PR, but failed to follow all the chain of indirections in #203 to find what to do.

bitprophet commented 9 years ago

I skimmed the blog post but it's unclear exactly what we need to add in Invoke itself for this? Do we need a __main__.py like Fabric's (which iirc was added for the same reason)? - eg https://github.com/fabric/fabric/blob/master/fabric/__main__.py

Given you mentioned #203 I'm guessing you were trying to alter the actual tasks for uploading, which implies something else is required, but most of that stuff is solely convenience. Ideally just downloading Invoke and doing python setup.py sdist register upload is sufficient (and it's what I do whenever the internal tasks break or need updating).

Which in turn means - hopefully all we need to modify is setup.py or something like aforementioned __main__.py - and not a "process" update. But let me know what the specifics are!

techtonik commented 9 years ago

Mixing packaging and build system is one big mistake about distutils architecture. =) I'll am close to preparing a proof of concept for my hexdump package, after which I may be able to split my blog post into several more muncheable ones, so it will become more clear what to do.

Because I failed to run invoke from source, it is unlikely that I will prepare a PR myself. If a tool is hard to hack on and has a lot of dependencies, maybe it is not the tool that I need.

bitprophet commented 9 years ago

To be fair (and to echo @sophacles in the other thread) Invoke follows a pretty standard method of development in the Python world, which is why I keep thinking there's just some miscommunication here :)

techtonik commented 9 years ago

Autotools is also a standard method in Unix world, but it doesn't mean it rocks.

Here, ready, take a look on how hexdump can be used from command line. It suits pretty much a lot of workflow.- https://pypi.python.org/pypi/hexdump - I wasted a week trying to figure out how to get all that together. Whew. =)

sophacles commented 9 years ago

A couple of things -

First, I am starting to wonder about having the tasks.py in invoke require an external repository installed is a good idea - it does somewhat hinder rapid understanding.

Just trying to use invoke as provided by the repository results in a weird error:

Traceback (most recent call last):
  File "/usr/local/Cellar/python/2.7.7_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 162, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/usr/local/Cellar/python/2.7.7_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "/Users/eheine/src/projects/invoke/invoke/__main__.py", line 2, in <module>
    main()
  File "invoke/cli.py", line 352, in main
    dispatch(sys.argv)
  File "invoke/cli.py", line 337, in dispatch
    args, collection, parser_contexts = parse(argv, version=version)
  File "invoke/cli.py", line 196, in parse
    collection = loader.load(coll_name) if coll_name else loader.load()
  File "invoke/loader.py", line 52, in load
    module = imp.load_module(name, fd, path, desc)
  File "/Users/eheine/src/projects/invoke/tasks.py", line 6, in <module>
    from invocations import docs as _docs
ImportError: No module named invocations

And it's not clear the taskfile is requiring this, rather than invoke itself. (This is true even after doing:

erich-heines-macbook-pro:invoke eheine$ mkvirtualenv foo
New python executable in foo/bin/python2.7
Also creating executable in foo/bin/python
Installing setuptools, pip...done.
(foo)erich-heines-macbook-pro:invoke eheine$ pip install .
Unpacking /Users/eheine/src/projects/invoke
  Running setup.py (path:/var/folders/9j/4pr6_hf111gcyjjr60z_vls00000gn/T/pip-W5I1_H-build/setup.py) egg_info for package from file:///Users/eheine/src/projects/invoke

    warning: no files found matching '*' under directory 'docs'
    warning: no previously-included files matching '*' found under directory 'docs/_build'
    warning: no previously-included files matching '*.pyo' found under directory 'tests'
Installing collected packages: invoke
  Running setup.py install for invoke
      File "/Users/eheine/envs/foo/lib/python2.7/site-packages/invoke/vendor/yaml3/__init__.py", line 284
        class YAMLObject(metaclass=YAMLObjectMetaclass):
                                  ^
    SyntaxError: invalid syntax

    warning: no files found matching '*' under directory 'docs'
    warning: no previously-included files matching '*' found under directory 'docs/_build'
    warning: no previously-included files matching '*.pyo' found under directory 'tests'
    Installing inv script to /Users/eheine/envs/foo/bin
    Installing invoke script to /Users/eheine/envs/foo/bin
Successfully installed invoke
Cleaning up...
(foo)erich-heines-macbook-pro:invoke eheine$ inv
Traceback (most recent call last):
  File "/Users/eheine/envs/foo/bin/inv", line 9, in <module>
    load_entry_point('invoke==0.9.0', 'console_scripts', 'inv')()
  File "/Users/eheine/envs/foo/lib/python2.7/site-packages/invoke/cli.py", line 352, in main
    dispatch(sys.argv)
  File "/Users/eheine/envs/foo/lib/python2.7/site-packages/invoke/cli.py", line 337, in dispatch
    args, collection, parser_contexts = parse(argv, version=version)
  File "/Users/eheine/envs/foo/lib/python2.7/site-packages/invoke/cli.py", line 196, in parse
    collection = loader.load(coll_name) if coll_name else loader.load()
  File "/Users/eheine/envs/foo/lib/python2.7/site-packages/invoke/loader.py", line 52, in load
    module = imp.load_module(name, fd, path, desc)
  File "/Users/eheine/src/projects/invoke/tasks.py", line 6, in <module>
    from invocations import docs as _docs
ImportError: No module named invocations

)

Rather having a self contained file that can be referenced and used with just invoke installed is a nice dogfood example. Tracking down the invocations package is a bit much to just use invoke.

Second, to make invoke usable via python -m it is a simple matter of adding a single __main__.py file to the invoke module directory. This file would literally be:

from cli import main
main()

Not sure if that is a good idea or not, but it is simple.

All that being said - I remember being a young programmer and not trusting the tools and environments and best practices. Turns out that I was wrong - the tools are a bit complicated for a reason: there are often a lot of edge cases I don't think of at first, and on encountering them and fixing them, my solution starts looking an awful lot like the already existing tools which already handle the same cases (and most of the time more!). Simple is great, but overly simple and NIH are basically the same thing in terms of results - the wheel is reinvented. Turns out sometimes the simple solution is just buying a wheel.