Skip to content
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

Add pre and post commands #1000

Merged
merged 3 commits into from
Sep 20, 2018
Merged

Add pre and post commands #1000

merged 3 commits into from
Sep 20, 2018

Conversation

gaborbernat
Copy link
Member

@gaborbernat gaborbernat commented Sep 18, 2018

Resolves #167.
Resolves #1003.
Resolves #1004.
Fixup for #987 and #851.

PS. Once we resolve and merge this we'll release 3.4.0.

@gaborbernat gaborbernat requested a review from a team September 18, 2018 20:57
@@ -532,6 +542,31 @@ def tox_runtest(venv, redirect):
return True # Return non-None to indicate plugin has completed


@tox.hookimpl
def tox_runtest_pre(venv):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these should be separate hooks for maximum compatibility with previous plugins implementing these (otherwise this is an added responsibility that every existing plugin that implements tox_runtest_pre now needs to also do!)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only added responsibility we're implying here is that the venv.status should be still zero after tox_runtest_pre. I don't think anyone modified that until now 🤔 So what other responsibilities am I missing? (would prefer not to add new hooks, to pollute our hook namespace even more).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah ok, these aren't firstresult=True (they maybe should be? hard to say) nevermind this then

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only the commands are first result 👍 the setup and teardown (pre and post) are not. And makes sense as while we don't want users to execute the command evaluation multiple times; we do want to allow them to setup/teardown their plugin.

@asottile
Copy link
Contributor

jfc codecov SETTLE DOWN 😆

@tox-dev tox-dev deleted a comment from codecov bot Sep 19, 2018
@tox-dev tox-dev deleted a comment from codecov bot Sep 19, 2018
@tox-dev tox-dev deleted a comment from codecov bot Sep 19, 2018
@tox-dev tox-dev deleted a comment from codecov bot Sep 19, 2018
@tox-dev tox-dev deleted a comment from codecov bot Sep 19, 2018
@tox-dev tox-dev deleted a comment from codecov bot Sep 19, 2018
@tox-dev tox-dev deleted a comment from codecov bot Sep 19, 2018
@tox-dev tox-dev deleted a comment from codecov bot Sep 19, 2018
@tox-dev tox-dev deleted a comment from codecov bot Sep 19, 2018
@tox-dev tox-dev deleted a comment from codecov bot Sep 19, 2018
@tox-dev tox-dev deleted a comment from codecov bot Sep 19, 2018
@tox-dev tox-dev deleted a comment from codecov bot Sep 19, 2018
@tox-dev tox-dev deleted a comment from codecov bot Sep 19, 2018
@tox-dev tox-dev deleted a comment from codecov bot Sep 19, 2018
@tox-dev tox-dev deleted a comment from codecov bot Sep 19, 2018
@codecov
Copy link

codecov bot commented Sep 19, 2018

Codecov Report

Merging #1000 into master will decrease coverage by 0.21%.
The diff coverage is 81.48%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1000      +/-   ##
==========================================
- Coverage   69.78%   69.57%   -0.22%     
==========================================
  Files          14       14              
  Lines        3406     3435      +29     
  Branches      453      458       +5     
==========================================
+ Hits         2377     2390      +13     
- Misses        965      980      +15     
- Partials       64       65       +1
Impacted Files Coverage Δ
src/tox/package.py 57.67% <0%> (-1.25%) ⬇️
src/tox/config.py 65.1% <100%> (-0.47%) ⬇️
src/tox/session.py 77.72% <50%> (ø) ⬆️
src/tox/venv.py 76.26% <90.47%> (+0.38%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 70bfb83...f70c541. Read the comment docs.

@gaborbernat gaborbernat changed the title [WIP] Add pre and post commands Add pre and post commands Sep 19, 2018
@gaborbernat
Copy link
Member Author

@asottile While trying to write tests for this and making them pass discovered two feature request that helped me understand what's happening

  • reasoning for venv recreation,
  • only update-ing .tox.config1 when it changes, not always;

And two user affecting bugs:

  • PEP-517 packaging
  • and command quoting being incorrect.

And two internal bugs (thing happened to work by chance, but not by design):

  • python md5 being zero when there were dependencies because of variable re-usage;
  • and pragma no cover being ignored.

As such this PR became a sort of longer one. However due to the iterative nature of these would be troublesome to split it up. As such I would appreciate to review and merge it as one.

@@ -69,7 +69,7 @@ def cmd(request, capfd, monkeypatch):
request.addfinalizer(py.path.local().chdir)

def run(*argv):
key = str(b"PYTHONPATH")
key = b"PYTHONPATH" if six.PY2 else "PYTHONPATH"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"native" string can just be str("PYTHONPATH") -- though as written is just as explicit and correct

@@ -69,7 +69,7 @@ def cmd(request, capfd, monkeypatch):
request.addfinalizer(py.path.local().chdir)

def run(*argv):
key = str(b"PYTHONPATH")
key = b"PYTHONPATH" if six.PY2 else "PYTHONPATH"
python_paths = (i for i in (str(os.getcwd()), os.getenv(key)) if i)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, I can't think of a situation where getcwd() returns non-native string -- I suspect the str(...) call here is superfluous

try:
ret = res._popen(cmd, **kwargs)
except tox.exception.InvocationError as exception: # pragma: no cover
ret = exception # pragma: no cover
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3: this no cover comment shouldn't be necessary since the except block itself is no-covered


# need to start with an empty (but existing) source distribution folder
if config.distdir.exists():
config.distdir.remove(rec=1, ignore_errors=True)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

potential race here (exists check finishes, other process creates), though I suspect it doesn't matter -- though could this just be config.distdir.remove(rec=1, ignore_errors=True)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that was my first solution, until the test started failing; seems rec=1 is only active if the folder exists because of https://github.com/pytest-dev/py/blob/master/py/_path/local.py#L204. Long story short you can only delete if already exists...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦‍♂️ :man_gesturing_no: 😭

else:
self.verbosity1(" {}$ {} ".format(popen.cwd, cmd))
self.verbosity1(" {}$ {} ".format(popen.cwd, cmd_args_shell))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh nice, this is the shlex fix in the output?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah should be 👍

src/tox/venv.py Outdated
@@ -35,13 +35,13 @@ def writeconfig(self, path):
lines.append("{} {}".format(*dep))
path.ensure()
path.write("\n".join(lines))
return lines
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(perhaps I'm not seeing it) is this return value used?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed not needed 👍

src/tox/venv.py Outdated
else self.deps == other.deps
)
)
def matches(self, other, deps_matches_subset=False, provide_reason=False):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function (if annotated) would be Union[Tuple[bool, str], bool] -- does it make sense to instead have two functions: one without the reason and one with the reason?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to avoid duplication of the logic though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yeah you can just do:

def whatever_with_reason(...):
    return True, 'reason'

def whatever_without_reason(...):
    ret, _ = whatever_with_reason(**kwargs)
    return ret

or something like that 🤷‍♂️

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, my idea was that only makes the code more type correct; which is not really needed until we implement type annotations (probably once we drop Python 2 and 3.4).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yeah I guess I didn't put my justifcation, my bad!

It would also be nice so we don't have a boolean trap parameter -- especially until there's enforced keyword-only-arguments in python3 they're a pretty easy pit to fall into in python where you accidentally pass too many positional arguments and it splats over a defaulted keyword argument

name = output.strip()
args = [self.envconfig.envpython, "-c", "import sys; print(sys.path)"]
name = next(
(i for i in output.split("\n") if i and not i.startswith("pydev debugger:")), ""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this left over from a debugging session?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More like a small fixup 👍 Ideally people should be able to run the test suite in debug mode too with pydev (both eclipse and Pycharm). For that to work this is needed.

@@ -107,7 +107,6 @@ branch = true
[coverage:report]
skip_covered = True
show_missing = True
exclude_lines = if __name__ == ["']__main__["']:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gaborbernat
Copy link
Member Author

Made PR feedback; not all should be ok.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants