-
-
Notifications
You must be signed in to change notification settings - Fork 151
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
Support session dependencies (requires
)
#631
Conversation
requires
)
requires
)requires
)
3e48a6f
to
dc4af45
Compare
https://github.com/gschaffner/nox/tree/share-venv branches off of this to also add a working implementation for #167. Demo: (click to expand)
nox.options.error_on_external_run = True
nox.options.sessions = ("a", "b")
@nox.session(python="3.10")
def env1(session):
session.install("pytest")
@nox.session(venv="env1")
def a(session):
print(f" v Should be 3.10")
session.run("python", "-V")
# pytest is available to this session.
print(" v Should show pytest stderr below.")
session.run("pytest", "cause_pytest_to_print_stderr")
@nox.session(python="3.9", requires=["env1"])
def b(session):
# pytest is not available to this session---it depends on env1 as as a prerequisite,
# but it does not share env1's venv.
print(" v Should log either 'pytest not found' or an error_on_external_run error.")
session.run("pytest", "-h")
@nox.session(python=["3.9", "3.10"])
def env2(session):
session.install("pytest")
@nox.session(python="3.10", venv="env2-{python}")
def c(session): pass
# e.g. `nox -s c` will run [env2-3.10, c] but not env2-3.9
@nox.session(python=["3.9", "3.10"], venv="env2-{python}")
def d(session): pass
# e.g. `nox -s d` will run [env2-3.9, d-3.9, env2-3.10, d-3.10]
@nox.session(python=False, venv="env1-{python}")
def e(session): pass
# e.g. `nox -s e` will raise since the requested venv does not exist I imagine that #167 should be handled in a separate PR after/if this PR is merged, though. |
dc4af45
to
6ac01a9
Compare
Hey @gschaffner This is an impressive piece of work! Thanks for all effort you've clearly put in. I'll go through it all soon and add some comments/thoughts but for now I think agree with most of your opinions on how the topo sort should behave wrt lazy/stable.
I agree with this so long as it won't adversely affect people who don't use the requires features. My main thoughts so far from a quick scan through are:
Is it worth marking this PR as draft for now then? I'd love to get some other maintainers eye's on this as it's pretty sizeable but great work! |
I am a soft "no" on Nox having a full dependency graph for sessions. I envisioned Nox as a very small tool, and one of the early decisions was not to try to do what That said, I am not a BDFL and I don't take a very active role in Nox's new features. If any active maintainer wants this, make it so. |
6ac01a9
to
7f4c49e
Compare
Hi all, sorry for the delay! I just fixed the minor
included, I believe. Even if this doesn't get merged into upstream Nox, I wanted to add tests to this (in part since we've been using it at my workplace for a month) :)
Yep, it would not affect users who don't use the
I totally agree, there is a big benefit to keeping tools small and targeted. At the same time though I think this has the potential to be useful to quite a few people who want to use a single tool without having to add complexity by wrapping their
I'll post on the linked issues to hopefully bring some attention to this PR and https://github.com/gschaffner/nox/tree/share-venv from those who expressed interest in these features.
Done. The only thing missing still is documentation (and perhaps discussion). If there is interest in merging this into upstream Nox, it might be good to think about reviewing it in conjunction with https://github.com/gschaffner/nox/tree/share-venv, as I organized the code in this branch with the plan to make it very simple to add venv-sharing on top of it in https://github.com/gschaffner/nox/tree/share-venv. |
Great piece of work @gschaffner ! I do not currently have enough bandwidth to review the code, but as far as features are concerned, I think that it would be worth extending what you have done for using Concerning this mechanism, my other comment is also that Finally, it may become more readable to offer a dedicated Once again great proposal, and I hope that this will make its way to the main |
a9c717a
to
a1ed5c7
Compare
6d50509
to
067f841
Compare
@theacodes has said elsewhere (Discord?) that it's not a "soft no" anymore, so I've started working on this. Also, it's not a replacement for Make, since those tools are based on file regeneration. This is more like an inverse of the existing "notify". I'd like to add two things that would depend on this: the ability to share environments (#167), and some sort of support for building wheels and then using them (#740). I've rebased and added support for modern parameterizations. Current status:
|
64ab44a
to
5e4b6c8
Compare
Signed-off-by: Henry Schreiner <[email protected]>
Signed-off-by: Henry Schreiner <[email protected]>
Signed-off-by: Henry Schreiner <[email protected]>
Signed-off-by: Henry Schreiner <[email protected]>
Signed-off-by: Henry Schreiner <[email protected]>
d1f72a8
to
08cc132
Compare
I think this is ready. It would be nice to not require 3.9 & 3.10 when running the tests, but that could be fixed later, and you can always skip the tests (unless someone knows a good way to mock the interpreters with the unversioned interpreter; I'd normally use pytest-subprocess for this). |
Signed-off-by: Henry Schreiner <[email protected]>
08cc132
to
ed02f1b
Compare
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 looks good to me.
Would it be possible to cut a new release to deliver this feature? It’s really needed. Thank you very much! |
Thank you for your response! No rush :) I just realized I can install directly from the source code (main branch), and it works like a charm. |
The more testing of our main branch out in the wild, the better for us (assuming you open issues if things break, that is)! :) |
Hi! This adds session dependency resolution support to close #453 and as a prerequisite for #167. This implementation works and is fully tested, but this PR still needs some documentation and discussion.
To get a topological sort of the dependency graph, I haven't used
graphlib.TopologicalSorter
or NetworkX DAG methods because I don't think that such sorters can give nox the desired behavior. The problem, essentially, is that we don't just want any topological sorter but a specific (unique, hopefully) topological sort that the user can exert some ordering preference over. For example:For this noxfile I would expect the following behavior:
nox -s e
runsc, e
.nox -s d a
runsc, e, d, b, a
. Note thatd
and its dependencies run beforea
and its dependencies.nox -s a d
runsc, b, a, e, d
. Note thata
and its dependencies run befored
and its dependencies. Also note thatc
runs beforeb
; I'll get to the reasoning for this in a moment.The problem with using
graphlib.TopologicalSorter
or NetworkX DAG methods is twofold:These sorters/methods take as argument just the graph. One cannot specify that they want only a topological sort of the subgraph specifically containing the
-s
sessions and their dependencies. That is, in the examples above, nox should not runf
becausef
is not a (direct or recursive) dependency of any of the sessions specified by-s
.One could work around this issue by using e.g.
graphlib.TopologicalSorter
to produce a topological sort of the entire graph, and then drop from this sort anything in{f and its recursive dependencies} - {*{node and its recursive dependencies} for node in (sessions listed in -s)}
. This is still more computationally expensive than it needs to be though, although this should have minimal effect for typical noxfile-sized graphs.Crucially:
graphlib.TopologicalSorter
andnetworkx.topological_sort
give no guarantee over which topological sort you get; they just guarantee that you get some topological sort. (The other NX topo. sorter,networkx.lexicographical_topological_sort
, does give a unique sort, but I don't think that it can be used to produce the desired behavior still.)For nox's behavior to be deterministic, though, we want a specific topological sort1. For example, in the example above, all of the following are valid topological sorts for subgraph for
nox -s a d
(i.e. the subgraph containing onlya
,d
, and their recursive dependencies):c, b, a, e, d
# the desired sort for nox -s a d ?b, c, a, e, d
# the desired sort for nox -s a d ?c, e, b, a, d
b, c, e, a, d
c, b, e, a, d
c, e, d, b, a
# the desired sort for nox -s d ab, c, e, d, a
c, b, e, d, a
c, e, b, d, a
I would argue that (i) is the desired sort for
nox -s a d
because it ise
does not run any earlier than is required ford
.a
and its dependencies befored
and its dependencies sincea
occurred befored
in the-s
listing. Similarly, it runsc
beforeb
sincec
occurred beforeb
ina
'srequires
.(ii) almost satisfies the same properties, but it is not stable in
b
andc
. The way that the dependency resolver can choose between (1) and (2) without leaving this choice as an undefined implementation detail is by preferring to runb
andc
in the order that they appear ina
'srequires
. This is exactly analogous to how the resolver prefers to runa
andd
in the order that they occur in innox -s a d
.As a minor point, using
graphlib
would require nox to either vendor graphlib or depend on e.g.graphlib-backport
, which is a small third-party dependency that would be best to avoid for security.nox._resolver.lazy_stable_topo_sort
is a topological sorting algorithm with these properties. It can also detect what graph cycle prevented the subgraph from having a topological sort if the subgraph is cyclic. Its implementation is recursive, but I believe it is still best-case and worst-caseO(n)
wheren
is the number of nodes in the subgraph that a sort is requested for. I would love to hear if these properties also make sense to others.Another point of discussion for this is how
requires
should interact with filtering flags (-k
,-t
). I think that nox should not allow sessions to be accidentally run without their dependencies, i.e. the manifest filtering should be done first, followed by inserting the dependencies of the filtered queue into to the queue appropriately. Thoughts?More Examples
Change
a
in the above example toThen
nox -s a d
runsc, e, d, a
. The resolver ignores the order preferencea, d
and will instead rund
beforea
to satisfy the dependencya -> d
.Putting
{python}
inrequires
is also supported:Also see the
nox._resolver.lazy_stable_topo_sort
docstring andtests/test__resolver.py
for more examples and comments.1: It would also be great if the topo. sort was not just deterministic but was mathematically unique such that which sort nox uses is not simply an implementation detail but part of the spec. Uniqueness is hard though. In any case, I think nox should pin its topological sorting algorithm for stability, i.e. don't use an algorithm implemented in an external dependency that we can't pin since pinning it could break installs of other packages into the same venv (thus potentially breaking packaging of nox for most non-Nix package managers).