sashahart / vex

Run a command in the named virtualenv.
MIT License
372 stars 26 forks source link

Support for creating/deleting virtualenvs. #2

Closed heyLu closed 10 years ago

heyLu commented 10 years ago

I vote for "yes, it should do that".

I was just talking to a friend today, mentioning that I prefer how bundler handles this in the ruby world. You do a bundle install --path .bundle and it then installs everything into that directory. I'd love to have something similar to this.

But I disgress, vex --create and vex --delete or similar things would be amazing. You talked of a spec to someone else on HN, do you want one from me too? (You might already have something in mind, as you already mentioned the whole thing in the README.)

sashahart commented 10 years ago

Thanks for the issue!

I did have some existing thoughts on this - I thought I would add -m --make / -r --remove flags, with some other flags that can be used with --make. (I'm willing to bikeshed on the names of make and remove, but so far have been happy with these in analogy with e.g. virtualenvwrapper). I think I will just run virtualenv in a subprocess to avoid reimplementing it, and let its output come through. My main issue will be safety, since both make and especially remove are destructive operations.

I'll be working on this this week.

mafrosis commented 10 years ago

@sashahart Awesome! I've recently been using https://github.com/mafrosis/virtualenv-api/tree/dont-cwd to run unit tests for a setup.py and some other bits - would be awesome if Vex could cover this use-case via an API.

sashahart commented 10 years ago

For now I am sticking to the plan of just punting with a subprocess for the sake of getting done soon, with good guarantees of compatibility - maybe that can be upgraded in the future.

Unless I'm mistaken, virtualenvapi is also running a virtualenv subprocess?

mafrosis commented 10 years ago

It sure does. Possibly exposing an API for virtualenv is a little out of scope for vex..

sashahart commented 10 years ago

Oh, now I understand what you are saying. Yeah, I think that API should come from virtualenv itself so it's in-process (at worst, from a wrapper around virtualenv's Python API - for my purposes a library wrapping subprocesses is not a big enough improvement). In the future I could upgrade vex to use that in-process API. I don't want vex to export a virtualenv API, but if you have requirements or use cases for vex's Python API to be used externally then I'd love to hear about those in another issue.

sashahart commented 10 years ago

For those interested, preliminary work is on branch 'remove'. If you are interested in the issue and have time, please try it out and provide feedback. (If you are very risk-averse, try it in a virtual machine because the feature is made to remove directories.)

To give an example of how this might be done:

# get the branch
cd /tmp
git clone https://github.com/sashahart/vex
cd vex
git checkout origin/remove

# make a virtualenv to test in and install the branch there
virtualenv env
env/bin/pip install /tmp/vex

# check output of --help, should have guidance on using --remove
env/bin/vex --help

# make a dummy virtualenv to work in, then have vex activate it and then tear down
virtualenv removethis
env/bin/vex --remove --path removethis
# do whatever in the new virtualenv, then hit ctrl-d and see removal message
sashahart commented 10 years ago

and now there is also some first work on --make in the branch called make, aka origin/make. manual testing is a similar sort of procedure

git checkout origin/make
virtualenv makenv
makenv/bin/pip install /tmp/vex
makenv/bin/vex --help
makenv/bin/vex --make --path /tmp/removethistoo

as a preview of what this means - once I get these both tested and merged, it will be possible to do the following to create a virtualenv, work in it using bash, then tear it down with one command

vex -mr ephemeral bash
heyLu commented 10 years ago

Wow, that's cool! :sparkles:

I tried the make part, because that's what I usually want to do.

Some comments:

sashahart commented 10 years ago

Cool, thanks a lot for checking it out!

I just pushed a quick fix for relatively-specified --path with --make, it's just a new commit on origin/make Let me know anything else you find.

The feature of autocreating ~/.virtualenvs is in the works for --make (along with a few other things that are blocked on --make). .

sashahart commented 10 years ago

OK, it's autocreating the containing directory if it doesn't already exist. It will still throw OSError if the specified path involves creating multiple intervening paths, I don't think that I want that mkdir -p behavior.

heyLu commented 10 years ago

Works for me. :)

Any thoughts about detecting the current (project/directory based) virtualenv via a .vexrc file? (That should probably go in another issue and might be out of scope, but I don't want to spam you with issues. But I can move it if you want.)

(By the way, executing .venv/bin/vex vex vex --help is ... fun! :))

sashahart commented 10 years ago

I'm not yet sure what you are asking. If you just want to customize the location to use instead of ~/.virtualenvs you can do that from .vexrc, e.g.:

virtualenvs=~/something_else

vex will also honor $WORKON_HOME to help virtualenvwrapper users who already defined it in .bashrc or whatever.

I'm glad I'm not the only one who is amused by weird vex tricks.

heyLu commented 10 years ago

Mhh... somehow --remove doesn't seem to work for me, with or without --path. It also doesn't print any error, just not removes anything. I think I updated correctly and that I am on the correct branch, but maybe I did something wrong anyway?

sashahart commented 10 years ago

I am very interested in why --remove is failing for you and want to fix that ASAP.

This isn't your fault, it's mine, but I can't reproduce right now (i.e.: it is working for me right now with or without --path).

In case this is rooted in a doc confusion (after all I didn't doc this yet) - note what --remove does: it activates the environment, THEN removes it when the launched process exits. (This allows it to combine with --make and is an 'adverb' to vex's normal thing, which is still effectively to substitute for the standard 'activate')

If you still find it isn't working, verify that you are using the same commit I am, here is my result from 'git rev-parse HEAD': 'b0c9234ab9a7b9f51824687c57200ed9773d4f53'

heyLu commented 10 years ago

I want to have a .vexrc in the project directory I'm working where the path to the virtualenv is specified. And I want vex to look for a (project-specific) .vexrc in the current directory and detect the configured virtualenv and just use that automatically. But given that you specify the environment as the first parameter, this might not be feasible, I don't know.

Example shell session:

$ cd ~/projects/python/awesome-soup
$ cat .vexrc
virtualenv=~/.virtualenvs/awesome-soup
$ vex pip install lots-of-forks
# installs to ~/.virtualenvs/awesome-soup

Alternatively, have a canonical virtualenv in the current directory to look for, like .vex-virtualenv or something like that. Again, this might be different from what you want.

In the meantime, I can just use a script that does vex $(basename $PWD) $@ or vex .venv $@.

sashahart commented 10 years ago

Got it! To keep this short: at one point I was considering a project/virtualenv-specific vexrc to support that kind of feature, but now I'm feeling increasingly skeptical about the benefit and I'm leaning strongly toward a separate utility for some of these other use cases. And as you alluded to, I definitely don't want to change the basic way that vex's args are composed (it breaks completion and gets confusing since the command is also optional).

But that said, if you want this feature and don't think there's a reasonable alternative, make a new issue with some compelling use cases and I'm willing to discuss use cases and approaches at absurd length until someone gets tired.

heyLu commented 10 years ago

Regarding --remove: I guess I was confused, I tried vex --remove env without an additional argument, if I use vex --remove env ls it removes env as expected.

However, why does vex --make env work, shouldn't that also require an additional argument?

heyLu commented 10 years ago

I'm think there are benefits to detecting the virtualenv automatically, but I also agree that it would be better to use a separate tool for that. One more similar to ruby's bundler, that also does dependency management. I don't think such a thing exists yet, but thanks to vex and pip, it might in the future. We'll see, maybe I'll write it.

So, no arguments for now. And again, thanks! :heart:

sashahart commented 10 years ago

Thanks for beating on this, I'm going to let you off the hook on any further testing since it is not your job :) In the end I will thrash it out with some automated cases probably over the weekend, but this manual monkeying is useful for deciding what to check on.

Anyway, I'm finding --make and --remove to behave symmetrically. Again, this is important to make sure we are not talking about different things, output from git rev-parse HEAD: make: 'b693b6719f174c52e48d98ba41474e7ce6bbf2f0' remove: 'b0c9234ab9a7b9f51824687c57200ed9773d4f53'

I've tried these cases with shell=bash in vexrc, with an empty vexrc, and with a nonexistent vexrc and in none of those 3 setups did I see an inconsistency.

# Both either run your shell or complain depending on value of $SHELL/shell= in vexrc
vex --make a1
vex --remove a1

# No complaint, there is a command
vex --make a2 ls
vex --remove a2 ls

# Both complain UNLESS shell= is set in vexrc
SHELL='' vex --make a3
SHELL='' vex --remove a3

The 'no command given' error is actually an unconditional check before make or remove logic even run, which means it happens before the code should even do anything different for --make vs. for --remove.

sashahart commented 10 years ago

Since I'm pretty happy with how these are shaking out I've combined them into one branch called make_remove, to be reviewed on PR #5. I'm closing this in favor of that.