Skip to content

Commit 4a52b2a

Browse files
tests/test_general.py: cope with stderr warnings with free threading.
1 parent 271b4ac commit 4a52b2a

File tree

1 file changed

+85
-26
lines changed

1 file changed

+85
-26
lines changed

tests/test_general.py

Lines changed: 85 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,20 @@
44
* Confirm proper release of file handles via Document.close()
55
* Confirm properly raising exceptions in document creation
66
"""
7-
import io
8-
import os
9-
107
import fnmatch
8+
import io
119
import json
12-
import pymupdf
10+
import os
1311
import pathlib
1412
import pickle
1513
import platform
14+
import pymupdf
1615
import re
16+
import shlex
1717
import shutil
1818
import subprocess
1919
import sys
20+
import sysconfig
2021
import textwrap
2122
import time
2223
import util
@@ -26,6 +27,15 @@
2627
scriptdir = os.path.abspath(os.path.dirname(__file__))
2728
filename = os.path.join(scriptdir, "resources", "001003ED.pdf")
2829

30+
Py_GIL_DISABLED = sysconfig.get_config_var('Py_GIL_DISABLED')
31+
try:
32+
gil_enabled = sys._is_gil_enabled()
33+
except AttributeError:
34+
gil_enabled = True
35+
regex_gil_stderr = None
36+
if Py_GIL_DISABLED and gil_enabled:
37+
regex_gil_stderr = '.*The global interpreter lock.*'
38+
2939

3040
def test_haslinks():
3141
doc = pymupdf.open(filename)
@@ -1038,10 +1048,10 @@ def check_lines(expected_regexes, actual):
10381048
'''
10391049
Checks lines in <actual> match regexes in <expected_regexes>.
10401050
'''
1041-
print(f'check_lines():', flush=1)
1042-
print(f'{expected_regexes=}', flush=1)
1043-
print(f'{actual=}', flush=1)
1051+
print(f'### check_lines():', flush=1)
10441052
def str_to_list(s):
1053+
if s is None:
1054+
return list()
10451055
if isinstance(s, str):
10461056
return s.split('\n') if s else list()
10471057
return s
@@ -1051,11 +1061,35 @@ def str_to_list(s):
10511061
expected_regexes.append('') # Always expect a trailing empty line.
10521062
# Remove `None` regexes and make all regexes match entire lines.
10531063
expected_regexes = [f'^{i}$' for i in expected_regexes if i is not None]
1054-
print(f'{expected_regexes=}', flush=1)
1055-
for expected_regex_line, actual_line in zip(expected_regexes, actual):
1056-
print(f' {expected_regex_line=}', flush=1)
1057-
print(f' {actual_line=}', flush=1)
1058-
assert re.match(expected_regex_line, actual_line)
1064+
1065+
print(f'expected_regexes ({len(expected_regexes)}):')
1066+
for i in expected_regexes:
1067+
print(f' {i!r}')
1068+
1069+
print(f'actual ({len(actual)}):')
1070+
for i in actual:
1071+
print(f' {i!r}')
1072+
1073+
i_expected = 0
1074+
i_actual = 0
1075+
while 1:
1076+
if i_expected == len(expected_regexes) and i_actual == len(actual):
1077+
break
1078+
print(f'expected {i_expected+1}/{len(expected_regexes)}')
1079+
print(f'actual {i_actual+1}/{len(actual)}')
1080+
assert i_expected < len(expected_regexes) and i_actual < len(actual)
1081+
expected_regex_line = expected_regexes[i_expected]
1082+
actual_line = actual[i_actual]
1083+
if expected_regex_line is None:
1084+
i_expected += 1
1085+
continue
1086+
print(f' expected_regex: {expected_regex_line!r}', flush=1)
1087+
print(f' actual: {actual!r}', flush=1)
1088+
match = re.match(expected_regex_line, actual_line)
1089+
print(f' {match=}')
1090+
assert match
1091+
i_expected += 1
1092+
i_actual += 1
10591093
assert len(expected_regexes) == len(actual), \
10601094
f'expected/actual lines mismatch: {len(expected_regexes)=} {len(actual)=}.'
10611095

@@ -1078,12 +1112,17 @@ def test_cli_out():
10781112
if os.environ.get('PYMUPDF_USE_EXTRA') == '0':
10791113
log_prefix = f'.+Using non-default setting from PYMUPDF_USE_EXTRA: \'0\''
10801114

1115+
sys.path.append(os.path.normpath(f'{__file__}/../..'))
1116+
try:
1117+
import pipcl
1118+
finally:
1119+
del sys.path[0]
1120+
pipcl.show_system()
10811121
def check(
10821122
expect_out,
10831123
expect_err,
10841124
message=None,
10851125
log=None,
1086-
verbose=0,
10871126
):
10881127
'''
10891128
Sets PYMUPDF_MESSAGE to `message` and PYMUPDF_LOG to `log`, runs
@@ -1095,39 +1134,44 @@ def check(
10951134
env['PYMUPDF_LOG'] = log
10961135
if message:
10971136
env['PYMUPDF_MESSAGE'] = message
1137+
command = 'pymupdf internal'
1138+
print(f'Running: {command}', flush=1)
1139+
if env:
1140+
print(f'with:')
1141+
for key in sorted(env.keys()):
1142+
print(f' {key}={shlex.quote(env[key])}')
10981143
env = os.environ | env
1099-
print(f'Running with {env=}: pymupdf internal', flush=1)
1100-
cp = subprocess.run(f'pymupdf internal', shell=1, check=1, capture_output=1, env=env, text=True)
1144+
cp = subprocess.run(command, shell=1, check=1, capture_output=1, env=env, text=True)
11011145

1102-
if verbose:
1103-
#print(f'{cp.stdout=}.', flush=1)
1104-
#print(f'{cp.stderr=}.', flush=1)
1105-
sys.stdout.write(f'stdout:\n{textwrap.indent(cp.stdout, " ")}')
1106-
sys.stdout.write(f'stderr:\n{textwrap.indent(cp.stderr, " ")}')
11071146
check_lines(expect_out, cp.stdout)
11081147
check_lines(expect_err, cp.stderr)
11091148

1110-
#
1149+
print(f'test_cli_out(): {Py_GIL_DISABLED=}')
1150+
print(f'test_cli_out(): {gil_enabled=}')
1151+
11111152
print(f'Checking default, all output to stdout.')
1153+
regex_gil_stderr = None
1154+
if Py_GIL_DISABLED and gil_enabled:
1155+
regex_gil_stderr = '.*The global interpreter lock.*'
11121156
check(
11131157
[
11141158
log_prefix,
11151159
'This is from PyMuPDF message[(][)][.]',
11161160
'.+This is from PyMuPDF log[(][)].',
11171161
],
1118-
'',
1162+
regex_gil_stderr,
11191163
)
11201164

11211165
#
11221166
if platform.system() != 'Windows':
11231167
print(f'Checking redirection of everything to /dev/null.')
1124-
check('', '', 'path:/dev/null', 'path:/dev/null')
1168+
check('', regex_gil_stderr, 'path:/dev/null', 'path:/dev/null')
11251169

11261170
#
11271171
print(f'Checking redirection to files.')
11281172
path_out = os.path.abspath(f'{__file__}/../../tests/test_cli_out.out')
11291173
path_err = os.path.abspath(f'{__file__}/../../tests/test_cli_out.err')
1130-
check('', '', f'path:{path_out}', f'path:{path_err}')
1174+
check('', regex_gil_stderr, f'path:{path_out}', f'path:{path_err}')
11311175
def read(path):
11321176
with open(path) as f:
11331177
return f.read()
@@ -1143,6 +1187,7 @@ def read(path):
11431187
'This is from PyMuPDF message[(][)][.]',
11441188
],
11451189
[
1190+
regex_gil_stderr,
11461191
log_prefix,
11471192
'.+This is from PyMuPDF log[(][)].',
11481193
],
@@ -1211,6 +1256,7 @@ def check(
12111256
'.+this is pymupdf.log[(][)]',
12121257
],
12131258
[
1259+
regex_gil_stderr,
12141260
'this is pymupdf.message[(][)] 2',
12151261
'.+this is pymupdf.log[(][)] 2',
12161262
],
@@ -1233,6 +1279,7 @@ def check(
12331279
log_prefix,
12341280
],
12351281
[
1282+
regex_gil_stderr,
12361283
'WARNING:pymupdf:this is pymupdf.message[(][)]',
12371284
'WARNING:pymupdf:.+this is pymupdf.log[(][)]',
12381285
],
@@ -1247,6 +1294,7 @@ def check(
12471294
''',
12481295
'',
12491296
[
1297+
regex_gil_stderr,
12501298
log_prefix,
12511299
'this is pymupdf.message[(][)]',
12521300
'.+this is pymupdf.log[(][)]',
@@ -1276,6 +1324,8 @@ def check(
12761324
log_prefix,
12771325
],
12781326
[
1327+
regex_gil_stderr,
1328+
log_prefix,
12791329
'WARNING:foo:this is pymupdf.message[(][)]',
12801330
'ERROR:foo:.+this is pymupdf.log[(][)]',
12811331
],
@@ -1300,6 +1350,8 @@ def check(
13001350
log_prefix,
13011351
],
13021352
[
1353+
regex_gil_stderr,
1354+
log_prefix,
13031355
'CRITICAL:pymupdf:this is pymupdf.message[(][)]',
13041356
'INFO:pymupdf:.+this is pymupdf.log[(][)]',
13051357
],
@@ -1316,7 +1368,9 @@ def check(
13161368
pymupdf.log('this is pymupdf.log()')
13171369
''',
13181370
[],
1319-
[],
1371+
[
1372+
regex_gil_stderr,
1373+
],
13201374
)
13211375

13221376

@@ -2026,10 +2080,15 @@ def test_4392():
20262080
# We get SEGV's etc with older swig.
20272081
if platform.system() == 'Windows':
20282082
assert (e2, e3) == (0xc0000005, 0xc0000005)
2029-
else:
2083+
elif platform.system() == 'Linux':
20302084
# On plain linux we get (139, 139). On manylinux we get (-11,
20312085
# -11). On MacOS we get (-11, -11).
20322086
assert (e2, e3) == (139, 139) or (e2, e3) == (-11, -11)
2087+
elif platform.system() == 'Darwin':
2088+
# python3.14t gives (4, -11)?
2089+
assert (e2, e3) == (-11, -11) or (e2, e3) == (4, -11)
2090+
else:
2091+
assert e2 and e3
20332092

20342093

20352094
def test_4639():

0 commit comments

Comments
 (0)