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-
107import fnmatch
8+ import io
119import json
12- import pymupdf
10+ import os
1311import pathlib
1412import pickle
1513import platform
14+ import pymupdf
1615import re
16+ import shlex
1717import shutil
1818import subprocess
1919import sys
20+ import sysconfig
2021import textwrap
2122import time
2223import util
2627scriptdir = os .path .abspath (os .path .dirname (__file__ ))
2728filename = 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
3040def 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
20352094def test_4639 ():
0 commit comments