-
-
Notifications
You must be signed in to change notification settings - Fork 617
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
Simplify BaseLogger attach APIs #1006
Conversation
I think the failure is unrelated. I still need to write some tests, though. |
@erip Thanks :) The file What do you think to add methods for |
Thanks for the comment @sdesrozis. I was thinking about the |
I suppose @vfdev-5 you agree ? |
Technically |
ERROR OF SDESROZIS! USED MY PHONE AND EDIT THE POST :( Sorry :( The code is correct - sdesrozis class BaseOutputHandler:
def __call__(self, x):
print("BaseOutputHandler", x)
class Engine:
def __init__(self):
self.handlers = []
def __call__(self, x):
for h in self.handlers:
h(x)
class BaseLogger:
output_handler_cls = BaseOutputHandler
def attach_output(self, e):
e.handlers.append(self.output_handler_cls())
class TbOutputHandler:
def __call__(self, x):
print("TbOutputHandler", x ** 2)
class TbLogger(BaseLogger):
output_handler_cls = TbOutputHandler
engine = Engine()
BaseLogger().attach_output(engine)
TbLogger().attach_output(engine)
engine(2)
> python test.py
> BaseOutputHandler 2
> TbOutputHandler 4 |
I was just thinking that approach myself. 😆 I think it's reasonable as long as we mark the |
@erip please go ahead with that approach :) |
Here I would prefer use interface to provide contract to implement for developers of logger. It's more or less the same but more constrained. What do you think about that ? from abc import ABCMeta, abstractmethod
class BaseOutputHandler:
def __call__(self, x):
print("BaseOutputHandler", x)
class Engine:
def __init__(self):
self.handlers = []
def __call__(self, x):
for h in self.handlers:
h(x)
class BaseLogger(metaclass=ABCMeta):
# should not provide an implementation
@abstractmethod
def output_handler(self):
pass
def attach_output(self, e):
e.handlers.append(self.output_handler())
class TbOutputHandler:
def __call__(self, x):
print("TbOutputHandler", x ** 2)
class TbLogger(BaseLogger):
def output_handler(self):
return TbOutputHandler()
engine = Engine()
# It don't work, BaseLogger is for inheritance
# BaseLogger().attach_output(engine)
TbLogger().attach_output(engine)
engine(2)
> python test.py
> TbOutputHandler 4 |
@sdesrozis agreed. Have a look at this - hopefully this fits your model. |
I should have defined In @abstract
def output_handler(self) -> BaseOutputHandler
pass And in concrete logger class MyOutputHandler(BaseOutputHandler):
....
class MyLogger(BaseLogger):
def output_handler(self) -> BaseOutputHandler
return MyOutputHandler I think my typehints is wrong : the good type is “class of BaseOutputHandler “ |
@sdesrozis or even more proper solution would be to dispatch those creators class BaseLogger:
@abstractmethod
def create_output_handler(self, *args, **kwargs) -> BaseOutputHandler
pass
def attach_output_handler(self, engine: Engine, event_name: str, *args: Any, **kwargs: Mapping):
engine.add_event_handler(event_name, self.create_output_handler(*args, **kwargs))
class MyOutputHandler(BaseOutputHandler):
....
class MyLogger(BaseLogger):
def create_output_handler(self, ) -> MyOutputHandler
return MyOutputHandler(*args, **kwargs) But a solution with class attributes is shorter :) EDIT: I think this is what was suggested by @sisp here : #901 (comment) |
That looks like the perfect pattern here! |
Abstract method is a guideline for developer. I prefer that but @erip chooses at the end 😊 I talk and I do nothing 😅 (except edit messages 😱) |
@erip I added the code with implementation of |
I think I've got the |
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.
Nice work 👍🏻
Returns: | ||
NeptuneLogger | ||
""" | ||
logger = NeptuneLogger() |
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 was thinking about those methods and loggers that need **kwargs to initialize.
Either we need to pass those things or directly work on the instance of such logger...
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 was thinking about this, too. I think the tricky thing is that the setup_X_logger
by convention passes in default kwargs. Adding *logger_constructor_args
and **logger_constructor_kwargs
isn't easy because of that. I think there are some clever things we could possibly do... will try to draft a gist quickly.
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.
See 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.
Like here ?
ignite/ignite/contrib/engines/common.py
Line 296 in 6624337
logger = VisdomLogger(**kwargs) |
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 that only works if it's a **kwargs-only constructor.
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 that only works if it's a **kwargs-only constructor.
Can’t test, I just have my phone 😅
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.
Ah, I was wrong. As long as we can guarantee the user specifies all constructor args they can pass it in as a dict at the end like in VisdomLogger
even for positional args.
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.
So let’s define defaults and that will be ok 👌🏻
Sorry I was too prompt to merge.
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.
Have #1015 out :-)
Seems like I was late before it waas merged :( |
@erip or @sdesrozis could you add that in another PR please |
Fixes #980
Description: Adds new interface, docstring, and implementations for simplified base_logger API.
Check list: