-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
[WIP][Showcase] dvc: use dynamic scope to stop callback/flag passing #2957
Conversation
@@ -131,3 +134,40 @@ def format_dict(self): | |||
d["ncols_desc"] = 1 | |||
d["prefix"] = "" | |||
return d | |||
|
|||
|
|||
# Adding this here for showcase only |
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.
👍
|
||
|
||
@contextmanager | ||
def _flags(stack, values): |
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.
woah, this is clever 👌
for d in reversed(self._stack): | ||
if name in d: | ||
return d[name] | ||
else: |
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.
Is this indented correctly?
|
||
class Noop: | ||
def __getattr__(self, name): | ||
return lambda self, *a, **kw: 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.
Isn't this the same as doing?
def __getattr__(self, name):
pass
from contextlib import contextmanager # noqa | ||
|
||
|
||
class ContextFlags: |
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.
@Suor , what about using this instead?
from contextlib import contextmanager
from collections import UserDict
class ContextFlags(UserDict):
def __getattr__(self, name):
return self.data.get(name)
@contextmanager
def __call__(self, **flags):
self.data.update(flags)
yield
for key in flags.keys():
del self.data[key]
I like the idea 👍 |
All right, @Suor! As I mentioned before, I like the approach. It reminds me a bit of Click's contexts So far, we've been trying to explicitly pass all the state/arguments needed for the execution (dependency injection, if you want to use a fancy name). I emphasize trying because we also rely on some external state (i.e. environment variables, configuration). The downside, is that having several nested calls require us to pass those arguments all the way down, for example (
I'd be more in favor of relying less on nesting calls and flatting the class hierarchy, but this is unlikely to happen soon (and would likely bring more pain than joy in the process -- heated discussions / holy wars). Introducing |
Interesting stuff! A few quick questions:
|
@Suor sorry for the late response |
If you don't specify a
If we decide at usage place, say method, e.g. flags.checkout_pbar.update_desc() # is a noop until set
flags.download_pbar.update(...) # raises unless set
The general idea is passing some info to all temporally scoped code without passing it explicitly, i.e. allowing higher level code speak with lower level one without everyone in the middle passing that. To use that for combining pbars we way use: # This says to any nesting pbars to be combined into this
with Tqdm(..., combine="download") as pbar:
# ... use it as is
# This behaves as usual unless under combine="download"
# When under that it updates that progress instead.
with Tqdm(..., action="download") as pbar:
# ... use it as is There would need to be some trickery to update totals and/or desc.
It already does |
Combining pbars might be implemented with explicit passing too though, which we might want to go after first. |
if not self.use_cache: | ||
if progress_callback: | ||
progress_callback(str(self.path_info), self.get_files_number()) | ||
pbar = flags.tqdm or noop |
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.
Maybe it would make sense to just have pbar
as a part of flags
or some other structure instead of doing flags.tqdm or noop
everywhere?
Sorry for an extremely late response from me, but this looks pretty nice. |
Closing as stale, maybe will come back to it in the future. |
The idea is to simplify function signatures and make intermediate calls not need to know when some high-level code is talking some low-level one.
Showcased on annoying enough
no_progress_bar
andprogress_callback
. Might be also used to simplify: