Allow to append command in venv run, not override
If command explicitly specified in dephell venv run original command will be overridden. Let's append command to the original one if it starts from plus sign:
dephell venv run --env=pytest +-x
It will add -x to the original command.
Kind of a funny syntax, at least not one I’ve seen before. Appending would just be for passing through options right? This is a syntax I’ve seen a few places (like npm run) which maybe is more standard?
dephell venv run --env=pytest -- -x
Here the -- means all the arguments after that point should be passed through to the inner command.
Thoughts?
If I want pass not the flag, it's difficult to understand it's binary or not. For example, test.py -- is it binary or positional argument? We can check if binary exists and pass it as argument otherwise, but it is not good by a few reason:
- Typo in binary name will cause running default command that you don't want to run
- If binary not found, dephell tries to install. If we will implement it, it will also try to install your arguments, that strange, dangerous, insecure, and slow.
Implicitly append passed flags to the command — good idea, let's do it. However, we need an explicit syntax for adding positional arguments, too.
I'm a bit confused, are you saying you don't like providing positional arguments after -- because it could be a typo?
Like someone typed dephell venv run -- env=pytest but meant dephell venv run --env=pytest?
Or maybe you're saying how do we differentiate between passing through positional arguments to configured command vs specifying a new command to run? The different would be:
- Passing through:
dephell venv run --env=pytest -- test.py - Running directly:
dephell venv run --env=pytest test.pyMaybe the difference just isn't explicit enough?
To clarify, my suggestion is that everything after -- be passed through to the inner command. So dephell venv run --env=pytest -- test.py -x --tb=short would basically be running pytest test.py -x --tb=short in the venv (assuming your command in config is just "pytest").
Here's a link to NPM where I took the idea from (https://docs.npmjs.com/cli/run-script)
What if you want to run something else in this env? For example, python. I don't think it's a good idea to make it impossible without changing config.
npm run script is about scripts, not envs. If you want to run some custom command, you are just not using script. However, we are talking about environments. In our case, using this behavior will require to activate environment to run custom command, run it, and then leave environment.
I think we're still not thinking along the same lines on this one, so let me type out a bit of an example to try and clarify further.
Let's say you have this in your pyproject.toml (taken directly from dephell's project):
[tool.dephell.flake8]
# read requirements file
from = {format = "pip", path = "requirements-flake.txt"}
# run this command
command = "flake8"
As I understand it, here's the way it works today:
Okay so you have an environment here called "flake8" with the default command of "flake8", cool. So if you do dephell venv run --env flake8 it will run the "flake8" command in the "flake8" environment.
Let's say you want to run "python" in that same environment, you do dephell venv run --env flake8 python.
None of this is new, I'm just making sure I'm not getting anything fundamentally wrong.
So (I think) the problem we're trying to solve is passing more parameters to whatever the default command is in the pyproject.toml. So let's say we want to pass a -q option to flake8. Today we could do this like dephell venv run --env flake8 flake8 -q but that's tedious right?
My suggestion (the addition of the -- separator) would make the syntax dephell venv run --env flake8 -- -q. This doesn't prevent someone from using the old syntax if they want to.
So from the perspective of the parser, these would be the valid ways to invoke the command:
-
dephell venv run --env {environment}: The basic case that exists today -
dephell venv run --env {environment} {positional command} {options for that command}: The case of overwriting the command, same as existing behavior -
dephell venv run --env {environment} -- {options for configured command}: New behavior for "appending" to configured command
Yes, you're right, and I agree with you. I'm talking about additional case when you want to specify positional arguments for the default command. In your example, if you want to run flake8 only against dephell directory. You can write this:
dephell venv run -- dephell
And dephell cannot infer that you want to run dephell or flake8 dephell. My idea is to use the first option by default and the second option if it's specified explicitly by plus sign.
Ah, maybe "options" was the wrong word. My suggestion is that everything after the lone -- be passed to the default command, even positional arguments. So then dephell venv run -- dephell explicitly means "pass 'dephell' to the configured command". If a positional argument is passed after a -- is encountered, pass it through like everything else. But we only allow the -- separator if no positional argument was provided. If the user were to do dephell venv run flake8 -- -q that would be an error, they aren't selecting the internal command so there's nothing to pass through to.
I'm not sure it's a good idea. -- can be used to terminate enumeration for list-based arguments in argparse:
dephell deps tree --envs main dev -- dephell
For now, only one such argument is --envs, and it's no meaning for venv run. So, maybe we can use it if we aren't going to add arguments like this for venv run.
For me, plus sign makes more sense because it means add: "add this to the command".
I think we need more opinions here. @b0g3r, could you share your thoughts if you have some?
I didn't know of existing functionality in argparse, so I looked it up. According to the docs I found, the -- is a special arg that does exactly what I said, it turns everything after it into a positional arg.
https://docs.python.org/3.3/library/argparse.html#arguments-containing
This actually probably makes my suggestion harder. Argparse swallows the -- so there's no way for us to know if it was passed before a positional argument was (unless I'm missing something in the docs?)
My only two thoughts then would be to either:
- make overriding the configured command an explicit option (
dephell venv run --command="mycommand"). Obviously this has the major downside of breaking the current API. - Include an
argparse.REMAINDERat the end instead of an explicit positional argument. Then we just check the first param to see if it's--or not.
I can check -- was passed or not. It's not a problem. Problem is that -- can passed for two different goals:
- Terminate list-argument input
- Say that it's arguments for existing command, not a new command.
So, you can't use list arguments and command overriding at the same time.
I don't want to make things over complicated. If plus sign isn't intuitive to you, it's better to close this issue. Because difference between command with and without -- isn't intuitive to me. -- sign used to indicate positional arguments for command. And both cases (additional arguments for subcommand and a new command) is positional arguments for dephell venv run
The plus-prepended options feels weird to me. Maybe we’re trying to be too fancy, we could just do a --append="extra --options here"