@@ -43,16 +43,24 @@ def __call__(self, *args: str) -> t.Sequence[t.Any]:
4343
4444
4545@pytest .fixture
46- def logger_mocker (mocker ) -> _TSetupMockProtocol :
46+ def logger_mocker (mocker ) -> t .Generator [_TSetupMockProtocol , None , None ]:
47+ original_levels = {}
48+
4749 def setup_mock (* logger_names ):
50+ nonlocal original_levels
51+
4852 loggers = [logging .getLogger (name ) for name in logger_names ]
4953 for logger in loggers :
50- logger .addHandler = mocker .Mock ()
51- logger .removeHandler = mocker .Mock ()
52- logger .setLevel = mocker .Mock ()
54+ original_levels [logger ] = logger .level
55+ mocker .patch .object (logger , "addHandler" )
56+ mocker .patch .object (logger , "removeHandler" )
57+ mocker .spy (logger , "setLevel" )
5358 return loggers
5459
55- return setup_mock
60+ yield setup_mock
61+
62+ for logger , level in original_levels .items ():
63+ logger .setLevel (level )
5664
5765
5866def test_watch_returns_watcher (logger_mocker ) -> None :
@@ -106,22 +114,21 @@ def test_watcher_context_manager(mocker) -> None:
106114 watcher .stop .assert_called_once ()
107115
108116
109- @pytest .mark .parametrize (
110- ("default_level" , "level" , "expected_level" ),
111- (
112- (None , None , logging .DEBUG ),
113- (logging .WARNING , None , logging .WARNING ),
114- (logging .WARNING , logging .DEBUG , logging .DEBUG ),
115- (logging .DEBUG , logging .WARNING , logging .WARNING ),
116- (1 , None , 1 ),
117- (None , 1 , 1 ),
118- )
117+ WATCH_ARGS = (
118+ #default_level, level, expected_level
119+ (None , None , logging .DEBUG ),
120+ (logging .WARNING , None , logging .WARNING ),
121+ (logging .WARNING , logging .DEBUG , logging .DEBUG ),
122+ (logging .DEBUG , logging .WARNING , logging .WARNING ),
123+ (logging .INFO , None , logging .INFO ),
124+ (logging .INFO , logging .DEBUG , logging .DEBUG ),
125+ (logging .DEBUG , logging .INFO , logging .INFO ),
126+ (1 , None , 1 ),
127+ (None , 1 , 1 ),
119128)
120- def test_watcher_level (
121- logger_mocker , default_level , level , expected_level
122- ) -> None :
123- logger_name = "neo4j"
124- logger = logger_mocker (logger_name )[0 ]
129+
130+
131+ def _setup_watch (logger_name , default_level , level ):
125132 kwargs = {}
126133 if default_level is not None :
127134 kwargs ["default_level" ] = default_level
@@ -131,9 +138,73 @@ def test_watcher_level(
131138 kwargs ["level" ] = level
132139 watcher .watch (** kwargs )
133140
141+
142+ @pytest .mark .parametrize (
143+ ("default_level" , "level" , "expected_level" ),
144+ WATCH_ARGS
145+ )
146+ @pytest .mark .parametrize (
147+ "effective_level" ,
148+ (logging .DEBUG , logging .WARNING , logging .INFO , logging .ERROR )
149+ )
150+ def test_watcher_level (
151+ logger_mocker , default_level , level , expected_level , effective_level ,
152+ ) -> None :
153+ logger_name = "neo4j"
154+ logger = logger_mocker (logger_name )[0 ]
155+ logger .setLevel (effective_level )
156+ logger .setLevel .reset_mock ()
157+ _setup_watch (logger_name , default_level , level )
158+
134159 (handler ,), _ = logger .addHandler .call_args
135- assert handler .level == logging .NOTSET
136- logger .setLevel .assert_called_once_with (expected_level )
160+ assert handler .level == expected_level
161+ if effective_level <= expected_level :
162+ logger .setLevel .assert_not_called ()
163+ else :
164+ logger .setLevel .assert_called_once_with (expected_level )
165+
166+
167+ @pytest .mark .parametrize (
168+ ("default_level1" , "level1" , "expected_level1" ),
169+ WATCH_ARGS
170+ )
171+ @pytest .mark .parametrize (
172+ ("default_level2" , "level2" , "expected_level2" ),
173+ WATCH_ARGS
174+ )
175+ @pytest .mark .parametrize (
176+ "effective_level" ,
177+ (logging .DEBUG , logging .WARNING , logging .INFO , logging .ERROR )
178+ )
179+ def test_watcher_level_multiple_watchers (
180+ logger_mocker , default_level1 , level1 , expected_level1 ,
181+ default_level2 , level2 , expected_level2 ,
182+ effective_level ,
183+ ) -> None :
184+ logger_name = "neo4j"
185+ logger = logger_mocker (logger_name )[0 ]
186+ logger .setLevel (effective_level )
187+ logger .setLevel .reset_mock ()
188+ _setup_watch (logger_name , default_level1 , level1 )
189+ _setup_watch (logger_name , default_level2 , level2 )
190+
191+ assert logger .addHandler .call_count == 2
192+ (handler1 ,), _ = logger .addHandler .call_args_list [0 ]
193+ (handler2 ,), _ = logger .addHandler .call_args_list [1 ]
194+
195+ assert handler1 .level == expected_level1
196+ assert handler2 .level == expected_level2
197+
198+ expected_logger_level = min (expected_level1 , expected_level2 )
199+ if effective_level <= expected_logger_level :
200+ logger .setLevel .assert_not_called ()
201+ else :
202+ if effective_level > expected_level1 > expected_level2 :
203+ assert logger .setLevel .call_count == 2
204+ else :
205+ assert logger .setLevel .call_count == 1
206+ (level ,), _ = logger .setLevel .call_args_list [- 1 ]
207+ assert level == expected_logger_level
137208
138209
139210custom_log_out = io .StringIO ()
@@ -220,6 +291,7 @@ def _assert_task_injection(
220291 handler_cls_mock = mocker .patch ("neo4j.debug.StreamHandler" , autospec = True )
221292 handler_mock = handler_cls_mock .return_value
222293 logger_name = "neo4j"
294+ logger_mocker (logger_name )[0 ]
223295 watcher = neo4j_debug .Watcher (logger_name , colour = colour ,
224296 thread_info = thread , task_info = task )
225297 record_mock = mocker .Mock (spec = logging .LogRecord )
0 commit comments