From 1390ac7f2d8a502ba4b5ea4d8d277479a9c9a6f9 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Thu, 14 Sep 2023 20:16:31 +0200 Subject: [PATCH 01/10] Add a command-line option to enable audit, using Python 3.8 sys.addaudithook() That's a debugging feature. Try '--audit os.mkdir,open' or '--audit all' --- picard/audit.py | 77 ++++++++++++++++++++++++++++++++++++++++++++++ picard/tagger.py | 10 ++++++ test/test_audit.py | 75 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+) create mode 100644 picard/audit.py create mode 100644 test/test_audit.py diff --git a/picard/audit.py b/picard/audit.py new file mode 100644 index 0000000000..ee07c4ae95 --- /dev/null +++ b/picard/audit.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +# +# Picard, the next-generation MusicBrainz tagger +# +# Copyright (C) 2023 Laurent Monin +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +from collections import defaultdict +import sys + + +def setup_audit(prefixes_string): + """Setup audit hook according to `audit` command-line option""" + if not prefixes_string: + return + if 'all' in prefixes_string.split(','): + def event_match(event): + return ('all', ) + else: + # prebuild the dict, constant + PREFIXES_DICT = make_events_prefixes(prefixes_string) + + def event_match(event): + return event_match_prefixes(event, PREFIXES_DICT) + + def audit(event, args): + # we can't use log here, as it generates events + matched = event_match(event) + if matched: + matched = '.'.join(matched) + print(f'audit:{matched}: {event} args={args}') + + sys.addaudithook(audit) + + +def make_events_prefixes(prefixes_string): + """Build a dict with keys = length of prefix""" + d = defaultdict(list) + for p in sorted(set(tuple(e.split('.')) for e in prefixes_string.split(',') if e)): + d[len(p)].append(p) + return d + + +def prefixes_candidates_for_length(length, prefixes_dict): + """Generate prefixes that may match this length""" + for plen, v in prefixes_dict.items(): + if length >= plen: + yield from v + + +def event_match_prefixes(event, prefixes_dict): + """Matches event against prefixes + Typical case: we want to match `os.mkdir` if prefix is `os` or `os.mkdir` + but not the reverse: if prefix is `os.mkdir` we don't want to match an event named `os` + It returns False, or the matched prefix + """ + ev = tuple(event.split('.')) + ev_len = len(ev) + # only use candidates that may have a chance to match + for p in prefixes_candidates_for_length(ev_len, prefixes_dict): + # check that all elements of ev are in p + if all(v == ev[i] for i, v in enumerate(p)): + return p + return False diff --git a/picard/tagger.py b/picard/tagger.py index 5c1f1dcf38..7bb9a79023 100644 --- a/picard/tagger.py +++ b/picard/tagger.py @@ -81,6 +81,7 @@ NatAlbum, run_album_post_removal_processors, ) +from picard.audit import setup_audit from picard.browser.browser import BrowserIntegration from picard.browser.filelookup import FileLookup from picard.cluster import ( @@ -256,6 +257,10 @@ def __init__(self, picard_args, localedir, autoupdate, pipe_handler=None): if picard_args.debug or "PICARD_DEBUG" in os.environ: self.set_log_level(logging.DEBUG) + if sys.version_info[:3] > (3, 8): + if picard_args.audit: + setup_audit(picard_args.audit) + # Main thread pool used for most background tasks self.thread_pool = QtCore.QThreadPool(self) # Two threads are needed for the pipe handler and command processing. @@ -1437,6 +1442,11 @@ def process_picard_args(): parser.add_argument("-display", nargs=1, help=argparse.SUPPRESS) # Picard specific arguments + if sys.version_info[:3] > (3, 8): + parser.add_argument("-a", "--audit", action='store', + default=None, + help="audit events passed as a comma-separated list, prefixes supported, " + "use all to match any (see https://docs.python.org/3/library/audit_events.html#audit-events)") parser.add_argument("-c", "--config-file", action='store', default=None, help="location of the configuration file") diff --git a/test/test_audit.py b/test/test_audit.py new file mode 100644 index 0000000000..cfdd432e28 --- /dev/null +++ b/test/test_audit.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# +# Picard, the next-generation MusicBrainz tagger +# +# Copyright (C) 2023 Laurent Monin +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +import sys +import unittest +from unittest.mock import patch + +from test.picardtestcase import PicardTestCase + +from picard.audit import ( + event_match_prefixes, + make_events_prefixes, + prefixes_candidates_for_length, + setup_audit, +) + + +class AuditTest(PicardTestCase): + def test_make_events_prefixes(self): + d = dict(make_events_prefixes('')) + self.assertEqual(d, {}) + d = dict(make_events_prefixes('a')) + self.assertEqual(d, {1: [('a',)]}) + d = dict(make_events_prefixes('a.b')) + self.assertEqual(d, {2: [('a', 'b')]}) + d = dict(make_events_prefixes('a.b,c.d,a.b')) + self.assertEqual(d, {2: [('a', 'b'), ('c', 'd')]}) + d = dict(make_events_prefixes('a,a.b,,a.b.c')) + self.assertEqual(d, {1: [('a',)], 2: [('a', 'b')], 3: [('a', 'b', 'c')]}) + + def test_prefixes_candidates_for_length(self): + d = make_events_prefixes('a,a.b,c.d,a.b.c,d.e.f,g.h.i') + self.assertEqual(list(prefixes_candidates_for_length(0, d)), []) + self.assertEqual(list(prefixes_candidates_for_length(1, d)), [('a',)]) + self.assertEqual(list(prefixes_candidates_for_length(2, d)), [('a',), ('a', 'b'), ('c', 'd')]) + expected = [('a',), ('a', 'b'), ('c', 'd'), ('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'h', 'i')] + self.assertEqual(list(prefixes_candidates_for_length(3, d)), expected) + self.assertEqual(list(prefixes_candidates_for_length(4, d)), expected) + + def test_event_match_prefixes(self): + d = make_events_prefixes('a.b') + self.assertEqual(event_match_prefixes('a', d), False) + self.assertEqual(event_match_prefixes('a.b', d), ('a', 'b')) + self.assertEqual(event_match_prefixes('a.b.c', d), ('a', 'b')) + self.assertEqual(event_match_prefixes('b.c', d), False) + + +@unittest.skipUnless(sys.version_info[:3] > (3, 8), "sys.addaudithook() available since Python 3.8") +class AuditHookTest(PicardTestCase): + def test_setup_audit_1(self): + with patch('sys.addaudithook') as mock: + setup_audit('a,b.c') + self.assertTrue(mock.called) + + def test_setup_audit_2(self): + with patch('sys.addaudithook') as mock: + setup_audit('') + self.assertFalse(mock.called) From 8cca0ab60e0b6292664c2d3d044071730a45daa4 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Fri, 15 Sep 2023 15:37:38 +0200 Subject: [PATCH 02/10] Add thread id and time since start to printed output ``` audit:os:216102:48.414292335510254 os.mkdir args=(b'/home/zas/.config/MusicBrainz', 511, -1) audit:open:216102:48.414377212524414 open args=(b'/home/zas/.config/MusicBrainz/.Picard.ini.synclock', 'a', 525377)audit:open:216130:10.849092245101929 open args=('/tmp/picardxd4csqqv.jpg', None, 655554) audit:open:216130:10.852484703063965 open args=(58, 'w', 524865) audit:open:216130:10.859289407730103 open args=(b'/home/zas/Musique/Budgie/The MCA Albums 1973-1975/3-02 Slipaway.flac', 'r', 524288) audit:open:216383:10.860839128494263 open args=(b'/home/zas/Musique/Budgie/The MCA Albums 1973-1975/3-03 Who Do You Want for Your Love_.flac', 'r', 524288) ``` --- picard/audit.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/picard/audit.py b/picard/audit.py index ee07c4ae95..1dfa491296 100644 --- a/picard/audit.py +++ b/picard/audit.py @@ -20,6 +20,8 @@ from collections import defaultdict import sys +import threading +import time def setup_audit(prefixes_string): @@ -36,12 +38,16 @@ def event_match(event): def event_match(event): return event_match_prefixes(event, PREFIXES_DICT) + start_time = time.time() + def audit(event, args): # we can't use log here, as it generates events matched = event_match(event) if matched: matched = '.'.join(matched) - print(f'audit:{matched}: {event} args={args}') + tid = threading.get_native_id() + secs = time.time() - start_time + print(f'audit:{matched}:{tid}:{secs} {event} args={args}') sys.addaudithook(audit) From ea0d4f5a13ec76c11558a0cd95cde593fc01f467 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Mon, 18 Sep 2023 09:12:35 +0200 Subject: [PATCH 03/10] make_events_prefixes() -> make_prefixes_dict() Not directly linked to audit events --- picard/audit.py | 4 ++-- test/test_audit.py | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/picard/audit.py b/picard/audit.py index 1dfa491296..cc394eece4 100644 --- a/picard/audit.py +++ b/picard/audit.py @@ -33,7 +33,7 @@ def event_match(event): return ('all', ) else: # prebuild the dict, constant - PREFIXES_DICT = make_events_prefixes(prefixes_string) + PREFIXES_DICT = make_prefixes_dict(prefixes_string) def event_match(event): return event_match_prefixes(event, PREFIXES_DICT) @@ -52,7 +52,7 @@ def audit(event, args): sys.addaudithook(audit) -def make_events_prefixes(prefixes_string): +def make_prefixes_dict(prefixes_string): """Build a dict with keys = length of prefix""" d = defaultdict(list) for p in sorted(set(tuple(e.split('.')) for e in prefixes_string.split(',') if e)): diff --git a/test/test_audit.py b/test/test_audit.py index cfdd432e28..2315a56fd7 100644 --- a/test/test_audit.py +++ b/test/test_audit.py @@ -26,27 +26,27 @@ from picard.audit import ( event_match_prefixes, - make_events_prefixes, + make_prefixes_dict, prefixes_candidates_for_length, setup_audit, ) class AuditTest(PicardTestCase): - def test_make_events_prefixes(self): - d = dict(make_events_prefixes('')) + def test_make_prefixes_dict(self): + d = dict(make_prefixes_dict('')) self.assertEqual(d, {}) - d = dict(make_events_prefixes('a')) + d = dict(make_prefixes_dict('a')) self.assertEqual(d, {1: [('a',)]}) - d = dict(make_events_prefixes('a.b')) + d = dict(make_prefixes_dict('a.b')) self.assertEqual(d, {2: [('a', 'b')]}) - d = dict(make_events_prefixes('a.b,c.d,a.b')) + d = dict(make_prefixes_dict('a.b,c.d,a.b')) self.assertEqual(d, {2: [('a', 'b'), ('c', 'd')]}) - d = dict(make_events_prefixes('a,a.b,,a.b.c')) + d = dict(make_prefixes_dict('a,a.b,,a.b.c')) self.assertEqual(d, {1: [('a',)], 2: [('a', 'b')], 3: [('a', 'b', 'c')]}) def test_prefixes_candidates_for_length(self): - d = make_events_prefixes('a,a.b,c.d,a.b.c,d.e.f,g.h.i') + d = make_prefixes_dict('a,a.b,c.d,a.b.c,d.e.f,g.h.i') self.assertEqual(list(prefixes_candidates_for_length(0, d)), []) self.assertEqual(list(prefixes_candidates_for_length(1, d)), [('a',)]) self.assertEqual(list(prefixes_candidates_for_length(2, d)), [('a',), ('a', 'b'), ('c', 'd')]) @@ -55,7 +55,7 @@ def test_prefixes_candidates_for_length(self): self.assertEqual(list(prefixes_candidates_for_length(4, d)), expected) def test_event_match_prefixes(self): - d = make_events_prefixes('a.b') + d = make_prefixes_dict('a.b') self.assertEqual(event_match_prefixes('a', d), False) self.assertEqual(event_match_prefixes('a.b', d), ('a', 'b')) self.assertEqual(event_match_prefixes('a.b.c', d), ('a', 'b')) From b8a0002fbe090eb378b491599f49482251731930 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Mon, 18 Sep 2023 09:21:53 +0200 Subject: [PATCH 04/10] event_match_prefixes() -> is_matching_a_prefix() This method isn't strictly related to events, but rather to dot-separated keys, use more generic names --- picard/audit.py | 16 ++++++++-------- test/test_audit.py | 12 ++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/picard/audit.py b/picard/audit.py index cc394eece4..e05d49cbce 100644 --- a/picard/audit.py +++ b/picard/audit.py @@ -36,7 +36,7 @@ def event_match(event): PREFIXES_DICT = make_prefixes_dict(prefixes_string) def event_match(event): - return event_match_prefixes(event, PREFIXES_DICT) + return is_matching_a_prefix(event, PREFIXES_DICT) start_time = time.time() @@ -67,17 +67,17 @@ def prefixes_candidates_for_length(length, prefixes_dict): yield from v -def event_match_prefixes(event, prefixes_dict): - """Matches event against prefixes +def is_matching_a_prefix(key, prefixes_dict): + """Matches dot-separated key against prefixes Typical case: we want to match `os.mkdir` if prefix is `os` or `os.mkdir` - but not the reverse: if prefix is `os.mkdir` we don't want to match an event named `os` + but not the reverse: if prefix is `os.mkdir` we don't want to match a key named `os` It returns False, or the matched prefix """ - ev = tuple(event.split('.')) - ev_len = len(ev) + skey = tuple(key.split('.')) + skey_len = len(skey) # only use candidates that may have a chance to match - for p in prefixes_candidates_for_length(ev_len, prefixes_dict): + for p in prefixes_candidates_for_length(skey_len, prefixes_dict): # check that all elements of ev are in p - if all(v == ev[i] for i, v in enumerate(p)): + if all(v == skey[i] for i, v in enumerate(p)): return p return False diff --git a/test/test_audit.py b/test/test_audit.py index 2315a56fd7..8d90cce0b2 100644 --- a/test/test_audit.py +++ b/test/test_audit.py @@ -25,7 +25,7 @@ from test.picardtestcase import PicardTestCase from picard.audit import ( - event_match_prefixes, + is_matching_a_prefix, make_prefixes_dict, prefixes_candidates_for_length, setup_audit, @@ -54,12 +54,12 @@ def test_prefixes_candidates_for_length(self): self.assertEqual(list(prefixes_candidates_for_length(3, d)), expected) self.assertEqual(list(prefixes_candidates_for_length(4, d)), expected) - def test_event_match_prefixes(self): + def test_is_matching_a_prefix(self): d = make_prefixes_dict('a.b') - self.assertEqual(event_match_prefixes('a', d), False) - self.assertEqual(event_match_prefixes('a.b', d), ('a', 'b')) - self.assertEqual(event_match_prefixes('a.b.c', d), ('a', 'b')) - self.assertEqual(event_match_prefixes('b.c', d), False) + self.assertEqual(is_matching_a_prefix('a', d), False) + self.assertEqual(is_matching_a_prefix('a.b', d), ('a', 'b')) + self.assertEqual(is_matching_a_prefix('a.b.c', d), ('a', 'b')) + self.assertEqual(is_matching_a_prefix('b.c', d), False) @unittest.skipUnless(sys.version_info[:3] > (3, 8), "sys.addaudithook() available since Python 3.8") From 427ed95d1591542db9354f1acb3c6965b66d9680 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Mon, 18 Sep 2023 09:22:35 +0200 Subject: [PATCH 05/10] make_prefixes_dict(): defaultdict is only used during building, returns a dict --- picard/audit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/picard/audit.py b/picard/audit.py index e05d49cbce..fef07496aa 100644 --- a/picard/audit.py +++ b/picard/audit.py @@ -57,7 +57,7 @@ def make_prefixes_dict(prefixes_string): d = defaultdict(list) for p in sorted(set(tuple(e.split('.')) for e in prefixes_string.split(',') if e)): d[len(p)].append(p) - return d + return dict(d) def prefixes_candidates_for_length(length, prefixes_dict): From 6a8053fcf0967614c187a27f1f7a3a251317eb1c Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Mon, 18 Sep 2023 10:36:38 +0200 Subject: [PATCH 06/10] make_prefixes_dict(): split code to list_from_prefixes_string() --- picard/audit.py | 13 +++++++++++-- test/test_audit.py | 12 ++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/picard/audit.py b/picard/audit.py index fef07496aa..51599145a0 100644 --- a/picard/audit.py +++ b/picard/audit.py @@ -52,11 +52,20 @@ def audit(event, args): sys.addaudithook(audit) +def list_from_prefixes_string(prefixes_string): + """Generate a sorted list of prefixes tuples + A prefixes string is a comma-separated list of dot-separated keys + "a,b.c,d.e.f,,g" would result in following sorted list: + [('a',), ('b', 'c'), ('d', 'e', 'f'), ('g',)] + """ + yield from sorted(set(tuple(e.split('.')) for e in prefixes_string.split(',') if e)) + + def make_prefixes_dict(prefixes_string): """Build a dict with keys = length of prefix""" d = defaultdict(list) - for p in sorted(set(tuple(e.split('.')) for e in prefixes_string.split(',') if e)): - d[len(p)].append(p) + for prefix_tuple in list_from_prefixes_string(prefixes_string): + d[len(prefix_tuple)].append(prefix_tuple) return dict(d) diff --git a/test/test_audit.py b/test/test_audit.py index 8d90cce0b2..45f83e0b7d 100644 --- a/test/test_audit.py +++ b/test/test_audit.py @@ -26,6 +26,7 @@ from picard.audit import ( is_matching_a_prefix, + list_from_prefixes_string, make_prefixes_dict, prefixes_candidates_for_length, setup_audit, @@ -33,6 +34,17 @@ class AuditTest(PicardTestCase): + def test_list_from_prefixes_string(self): + def f(s): + return list(list_from_prefixes_string(s)) + + self.assertEqual(f(''), []) + self.assertEqual(f('a'), [('a',)]) + self.assertEqual(f('a,b'), [('a',), ('b',)]) + self.assertEqual(f('a,,b'), [('a',), ('b',)]) + self.assertEqual(f('a.c,,b.d.f'), [('a', 'c'), ('b', 'd', 'f')]) + self.assertEqual(f('b.d.f,a.c,'), [('a', 'c'), ('b', 'd', 'f')]) + def test_make_prefixes_dict(self): d = dict(make_prefixes_dict('')) self.assertEqual(d, {}) From 8c268c2a5cbcf6c81a25163f4930aff2b24cfcd9 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Mon, 18 Sep 2023 10:37:16 +0200 Subject: [PATCH 07/10] prefixes_candidates_for_length(): rename variables to be more explicit --- picard/audit.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/picard/audit.py b/picard/audit.py index 51599145a0..933ab04687 100644 --- a/picard/audit.py +++ b/picard/audit.py @@ -71,9 +71,9 @@ def make_prefixes_dict(prefixes_string): def prefixes_candidates_for_length(length, prefixes_dict): """Generate prefixes that may match this length""" - for plen, v in prefixes_dict.items(): - if length >= plen: - yield from v + for prefix_len, prefixes in prefixes_dict.items(): + if length >= prefix_len: + yield from prefixes def is_matching_a_prefix(key, prefixes_dict): From f3e4736b2afc1bb25b47737b1429459748fd70b2 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Mon, 18 Sep 2023 10:38:03 +0200 Subject: [PATCH 08/10] is_matching_a_prefix(): use more explicit names for variables --- picard/audit.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/picard/audit.py b/picard/audit.py index 933ab04687..682eee2824 100644 --- a/picard/audit.py +++ b/picard/audit.py @@ -82,11 +82,11 @@ def is_matching_a_prefix(key, prefixes_dict): but not the reverse: if prefix is `os.mkdir` we don't want to match a key named `os` It returns False, or the matched prefix """ - skey = tuple(key.split('.')) - skey_len = len(skey) + key_tuple = tuple(key.split('.')) + key_tuple_len = len(key_tuple) # only use candidates that may have a chance to match - for p in prefixes_candidates_for_length(skey_len, prefixes_dict): - # check that all elements of ev are in p - if all(v == skey[i] for i, v in enumerate(p)): - return p + for prefix_tuple in prefixes_candidates_for_length(key_tuple_len, prefixes_dict): + # check that all elements of the key are in prefix tuple + if all(prefix_part == key_tuple[i] for i, prefix_part in enumerate(prefix_tuple)): + return prefix_tuple return False From 74942272c4b4a480f44ff5b4079426ee1f4acfc6 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Mon, 18 Sep 2023 10:47:55 +0200 Subject: [PATCH 09/10] Remove version checks, and use AttributeError exception to skip if needed --- picard/audit.py | 6 +++++- picard/tagger.py | 14 ++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/picard/audit.py b/picard/audit.py index 682eee2824..cf009268d4 100644 --- a/picard/audit.py +++ b/picard/audit.py @@ -49,7 +49,11 @@ def audit(event, args): secs = time.time() - start_time print(f'audit:{matched}:{tid}:{secs} {event} args={args}') - sys.addaudithook(audit) + try: + sys.addaudithook(audit) + except AttributeError: + # sys.addaudithook() appeared in Python 3.8 + pass def list_from_prefixes_string(prefixes_string): diff --git a/picard/tagger.py b/picard/tagger.py index 7bb9a79023..f4c643c199 100644 --- a/picard/tagger.py +++ b/picard/tagger.py @@ -257,9 +257,8 @@ def __init__(self, picard_args, localedir, autoupdate, pipe_handler=None): if picard_args.debug or "PICARD_DEBUG" in os.environ: self.set_log_level(logging.DEBUG) - if sys.version_info[:3] > (3, 8): - if picard_args.audit: - setup_audit(picard_args.audit) + if picard_args.audit: + setup_audit(picard_args.audit) # Main thread pool used for most background tasks self.thread_pool = QtCore.QThreadPool(self) @@ -1442,11 +1441,10 @@ def process_picard_args(): parser.add_argument("-display", nargs=1, help=argparse.SUPPRESS) # Picard specific arguments - if sys.version_info[:3] > (3, 8): - parser.add_argument("-a", "--audit", action='store', - default=None, - help="audit events passed as a comma-separated list, prefixes supported, " - "use all to match any (see https://docs.python.org/3/library/audit_events.html#audit-events)") + parser.add_argument("-a", "--audit", action='store', + default=None, + help="audit events passed as a comma-separated list, prefixes supported, " + "use all to match any (see https://docs.python.org/3/library/audit_events.html#audit-events)") parser.add_argument("-c", "--config-file", action='store', default=None, help="location of the configuration file") From 255ec01cd8caa57677c0af99684e0eab640ef845 Mon Sep 17 00:00:00 2001 From: Laurent Monin Date: Mon, 18 Sep 2023 14:43:55 +0200 Subject: [PATCH 10/10] Move comment where it makes more sense Suggested by phw --- picard/audit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/picard/audit.py b/picard/audit.py index cf009268d4..2e62409c89 100644 --- a/picard/audit.py +++ b/picard/audit.py @@ -41,12 +41,12 @@ def event_match(event): start_time = time.time() def audit(event, args): - # we can't use log here, as it generates events matched = event_match(event) if matched: matched = '.'.join(matched) tid = threading.get_native_id() secs = time.time() - start_time + # we can't use log here, as it generates events print(f'audit:{matched}:{tid}:{secs} {event} args={args}') try: