Closed rcthomas closed 2 years ago
@mbmilligan I've re-made the PR here so it's a bit cleaner and addresses a little disarray my fork had with it, sorry for any confusion
For this PR specifically, the main discussion about the problem and its "resolution" is in #44. There are hints about it in #24, but several of the open issues are mainly resolved by (closed) PR #45 such as #41.
Perhaps we can merge this PR and create an RC incorporating it and the work done in #45, and folks involved in those issues to test it and see if the issues reported there go away?
"Per discussion at the HPC call Tuesday", Is this due to @rcthomas being at Berkley and Berkley being industrial partners ?
Hi @jbeal-work, there's a monthly JupyterHub in HPC call, first Wednesday of each month, you can find it and other similar events on the Jupyter Community calendar, https://discourse.jupyter.org/t/jupyter-community-calendar/2485, please feel free to join us in February!
Have you been able to test this branch? If so, can you let us know how it went?
I have added the event in Febuarry to our groups diary. I will do my best to attend.
With the combination of this patch and the api one I have a web interface based around docker being able to submit jobs to our HPC clusters working so thank you very much.
if isinstance(spawner, ProfilesSpawner):
spawner = spawner.child_spawner
I am a bit confused why the system built with out docker did not need the patches but I suspect they are so disimular.
( I am pretty sure the hacks I have put in batchspawner should be config however I am not a python expert ).
( I am going to try converting the data notebooker docker image workin ( I understand I will need to inject batchspawner in to the image )).
FWIW, I tried @manics config and see no errors both with and without this patch. My env:
But I suspect the root is that .server
is an unnecessarily complex, cached property (not a trait) referencing .orm_spawner.server
, so it's possible a cached value is being stored as None, losing its connection to the underlying/wrapper Server object.
A big part is that server
is a property, not a trait. That means it can't be set via the constructor, as is attempted here. That line has no effect, though it should trigger this warning from traitlets:
# run with python -Wall test.py
from jupyterhub.spawner import SimpleLocalProcessSpawner
s = SimpleLocalProcessSpawner(server="xxx")
print(f"server={s.server}")
produces:
$PREFIX/lib/python3.9/site-packages/traitlets/config/configurable.py:85: DeprecationWarning: Passing unrecognized arguments to super(SimpleLocalProcessSpawner).__init__(server='xxx').
object.__init__() takes exactly one argument (the instance to initialize)
This is deprecated in traitlets 4.2.This error will be raised in a future release of traitlets.
super(Configurable, self).__init__(**kwargs)
server=None
The lack of environment variable is this retrieval in get_env(). I don't quite understand why triggering the property getter would result in the right behavior, when it's the exact same property getter that seems to return the wrong value in one test and not in the other (at least for @manics).
The fix is perhaps to redefine the .server
property on one class or the other to be a more direct link to the parent. However, redefining how properties work isn't something that's easy to do on instances - that's usually done on classes themselves. You could do:
class WrappedChild(self.child_class):
# keep our server property in sync with our wrapper
@property
def server(self):
return self.parent.server
@server.setter(self):
def server(self, new_server):
self.parent.server = new_server
self.child_spawner = WrappedChild(parent=self, ...)
Alternately, the new property could be implemented in WrapSpawner, but I think that's actually more complicated, since there isn't easy access to super()
in properties, so you'd have to duplicate private details of the .server property.
I think it would also work to clear the cached private ._server
value:
delattr(child_spawner, '_server')
but that's reaching into some pretty private details.
If we rewrote .server
in the base Spawner class as a trait instead of a property, the issue ought to go away, as the existing directional_link
code would pick it up.
Now that I think of it, it's possible that this simple link on WrapSpawner:
@property
def server(self):
return self.construct_child().server
@server.setter
def server(self, server):
self.construct_child().server = server
ought to work, relying on the 'canonical' implementation residing in the child.
Agreed this is mainly because Spawner.server
is not a trait and changing it to be such would fix this case. Thanks for verifying the proof of concept @manics.
The proposed property fix from @minrk is worth trying because it's much less mysterious looking than the vivification line. It could be documented in such a way that if an implementor comes up with yet another Spawner
attribute they need that isn't a trait and needs similar handling (e.g. manual directional linkage) they'd have a fighting chance of knowing what to do. It would be much better if everything could be handled without that but I imagine there are reasons not everything is a traitlet on Spawner
.
I'll set up and test this proposal out today.
See #51 for an alternative, based on Min's suggestion
I think this would also be fixed by https://github.com/jupyterhub/jupyterhub/pull/3810 which more rigorously keeps spawner.server
in sync with spawner.orm_spawner.server
. That PR has some explanation of why server isn't a trait (mainly that we can't observe secondary attributes like orm_spawner.server
, so we have to check on every access, which traitlets doesn't do).
Thanks @rcthomas and @minrk for thinking this through, I really like the alternative solution you've arrived at in #51. It sounds then like this PR should be closed in favor of merging that one.
Improved solution merged from PR #51
This addresses problems like #44 where the child_spawner.server attribute doesn't exist because it needs to be provoked into existing by hitting its getter. This part of the Spawner code shows how server comes into existence or not.
Per discussion at the HPC call Tuesday, we'll proceed by