On Tue, May 02, 2023 at 11:23:32AM +0200, Mads Ynddal wrote: > From: Mads Ynddal <[email protected]> > > Instead of explicitly calling `begin` and `end`, we can change the class > to use the context-manager paradigm. This is mostly a styling choice, > used in modern Python code. But it also allows for more advanced analyzers > to handle exceptions gracefully in the `__exit__` method (not > demonstrated here). > > Signed-off-by: Mads Ynddal <[email protected]> > --- > scripts/simpletrace.py | 40 +++++++++++++++++++++++----------------- > 1 file changed, 23 insertions(+), 17 deletions(-) > > diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py > index 7444a6e090..10ca093046 100755 > --- a/scripts/simpletrace.py > +++ b/scripts/simpletrace.py > @@ -121,12 +121,12 @@ def read_trace_records(event_mapping, event_id_to_name, > fobj): > > yield rec > > -class Analyzer(object): > +class Analyzer: > """A trace file analyzer which processes trace records. > > - An analyzer can be passed to run() or process(). The begin() method is > - invoked, then each trace record is processed, and finally the end() > method > - is invoked. > + An analyzer can be passed to run() or process(). The __enter__() method > is > + invoked when opening the analyzer using the `with` statement, then each > trace > + record is processed, and finally the __exit__() method is invoked.
Bearing in mind compatibility with existing simpletrace analysis
scripts, how about the following default method implementations?
def __enter__(self):
self.begin()
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is None:
self.end()
return False
Now simpletrace.py can switch to using the context manager and new
scripts can implement __enter__()/__exit__(), while old scripts continue
to work.
>
> If a method matching a trace event name exists, it is invoked to process
> that trace record. Otherwise the catchall() method is invoked.
> @@ -152,19 +152,25 @@ def runstate_set(self, timestamp, pid, new_state):
> ...
> """
>
> - def begin(self):
> + def __enter__(self):
> """Called at the start of the trace."""
> - pass
> + return self
>
> def catchall(self, event, rec):
> """Called if no specific method for processing a trace event has
> been found."""
> pass
>
> - def end(self):
> + def __exit__(self, _type, value, traceback):
> """Called at the end of the trace."""
> pass
>
> -def process(events, log, analyzer, read_header=True):
> + def __call__(self):
> + """Fix for legacy use without context manager.
> + We call the provided object in `process` regardless of it being the
> object-type or instance.
> + With this function, it will work in both cases."""
> + return self
> +
> +def process(events, log, analyzer_class, read_header=True):
Please don't change the function signature since this is a public method
and we should avoid breaking existing callers when possible.
Instead of:
with analyzer_class() as analyzer:
we can use:
with analyzer:
...
signature.asc
Description: PGP signature
