-
-
Notifications
You must be signed in to change notification settings - Fork 533
Isolate environment variable substitutions #521
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Isolate environment variable substitutions #521
Conversation
Perform `{env:X}` replacement only in environments where `X` is used. This enables different environments to use different subsets of the environment (e.g. don't require union of all passenv sections in all environments).
Can't speak for the code, but I've had this problem before too. |
Ping? |
Hi @AndreLouisCaron thanks for the fix. Can you quickly tell me why you are not confident that the fix is the best way to go forward? I did not check the code yet, just wanted to get more insight, before I review it. |
@obestwalter Some methods already had a |
o.k. thanks - I will take that into account and dig a bit through history to check whether there is some background to it. |
@@ -818,7 +819,7 @@ def make_envconfig(self, name, section, subs, config): | |||
atype = env_attr.type | |||
if atype in ("bool", "path", "string", "dict", "dict_setenv", "argv", "argvlist"): | |||
meth = getattr(reader, "get" + atype) | |||
res = meth(env_attr.name, env_attr.default) | |||
res = meth(env_attr.name, env_attr.default, replace=replace) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to reviewers: adding this here is why I needed to add a replace
argument all over the place.
@@ -787,7 +787,8 @@ def __init__(self, config, inipath): | |||
factors = set(name.split('-')) | |||
if section in self._cfg or factors <= known_factors: | |||
config.envconfigs[name] = \ | |||
self.make_envconfig(name, section, reader._subs, config) | |||
self.make_envconfig(name, section, reader._subs, config, | |||
replace=name in config.envlist) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to reviewers: this is the core of the change I wanted to make. Don't replace environment substitutions unless the environment is in envlist
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, my intent is to use replace=False
when the environment is not scheduled in the current run. I'm not 100% sure config.envlist
is what I want here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, my intent is to use replace=False when the environment is not scheduled in the current run.
Do you mean: all the runs scheduled in this invocation? e.g. tox -e py27,py34
would then only do substitutions for these two environments when parsing the ini?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's what I meant.
new_arg += new_word | ||
newcommand += new_arg | ||
else: | ||
newcommand = command |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to reviewers: the new else
clause here is essential to the change. When replace=False
, we should leave the command uninterpreted (we can't evaluate it since we're potentially missing some of the variables).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In combination with the current way of determining if replacements should happen that would mean though that it is possible that an environment that should run does not get any replacements if one of the variables is not set instead of rightfully crashing because there is a variable missing. Correct? I think I have create some example tox.ini and play this through to get my head around it though ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand your question. IMO, if you request to run an environment and we can't perform substitutions because something is missing, I would keep the existing behaviour (e.g. faily loudly) for the moment.
I agree that as a user, I would expect something else (e.g. run other envs, skip/fail the one(s) with the missing vars), but I would do that in a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh .. I was not notified that you answered here :)
Actually I also prefer failing, but I am not sure if this is happening. I have to look closer at the test and do some exploring myself. Thanks.
@obestwalter I added a few notes in the review to cue in on my reasoning. I hope it helps without skewing your independent review :-) |
Thanks, very appreciated :) |
@@ -953,12 +954,12 @@ def getlist(self, name, sep="\n"): | |||
return [] | |||
return [x.strip() for x in s.split(sep) if x.strip()] | |||
|
|||
def getdict(self, name, default=None, sep="\n"): | |||
def getdict(self, name, default=None, sep="\n", replace=True): | |||
value = self.getstring(name, None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self: may have forgotten the replace=replace
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so as well, should also be passed through to getstring.
I'll review and test this at the EuroPython tox sprint weekend and then it will likely be in 2.8. |
Thanks a bunch! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few questions are open - see comments
@@ -787,7 +787,8 @@ def __init__(self, config, inipath): | |||
factors = set(name.split('-')) | |||
if section in self._cfg or factors <= known_factors: | |||
config.envconfigs[name] = \ | |||
self.make_envconfig(name, section, reader._subs, config) | |||
self.make_envconfig(name, section, reader._subs, config, | |||
replace=name in config.envlist) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, my intent is to use replace=False when the environment is not scheduled in the current run.
Do you mean: all the runs scheduled in this invocation? e.g. tox -e py27,py34
would then only do substitutions for these two environments when parsing the ini?
@@ -953,12 +954,12 @@ def getlist(self, name, sep="\n"): | |||
return [] | |||
return [x.strip() for x in s.split(sep) if x.strip()] | |||
|
|||
def getdict(self, name, default=None, sep="\n"): | |||
def getdict(self, name, default=None, sep="\n", replace=True): | |||
value = self.getstring(name, None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so as well, should also be passed through to getstring.
new_arg += new_word | ||
newcommand += new_arg | ||
else: | ||
newcommand = command |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In combination with the current way of determining if replacements should happen that would mean though that it is possible that an environment that should run does not get any replacements if one of the variables is not set instead of rightfully crashing because there is a variable missing. Correct? I think I have create some example tox.ini and play this through to get my head around it though ...
elif word.startswith("{posargs:") and word.endswith("}"): | ||
if posargs: | ||
if replace: | ||
newcommand = "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be new_command
to be consistent with other variable names used around it
@obestwalter Can't reply directly to your comment.
Yes. |
Like I said, I'd like to answer, but I'm not sure I understand what your question is. |
o.k. - I'll merge this now and fix up anything that is not quite there yet (e.g. one missing passing of replace). Will test this today and cut a release candidate from it at some point at the weekend. @AndreLouisCaron it would be great if you test the rc then yourself a bit and check if everything is as it should be. |
Sorry, was on vacation the past 2 weeks and did not follow up. Thanks for proceeding with this! Let me know when the RC is up, I will gladly try it out :-) |
fix up #521: add missing pass of arg to underlying function.
@AndreLouisCaron - hope you had a nice holiday :) rc1 with your changes is out already. |
Perform
{env:X}
replacement only in environments whereX
is used. Thisenables different environments to use different subsets of the environment
(e.g. don't require union of all passenv sections in all environments).
Fixes #515.
Note to reviewers: this is a tentative fix. I'm definitely not sure how to best proceed with this fix. Feel free to recommend an alternate approach!