⊟
3.53 MB
/home/fdroid/fdroiddata/tmp/com.econverter.app_8.apk vs.
/home/fdroid/fdroiddata/unsigned/com.econverter.app_8.apk
⊟
8.2 KB
APK Signing Block
    
Offset 1, 121 lines modifiedOffset 0, 0 lines modified
1 Key·0x42726577: 
2 0000000000000000000000000000000000000000000000000000000000000000000000 
3 0000000000000000000000000000000000000000000000000000000000000000000000 
4 0000000000000000000000000000000000000000000000000000000000000000000000 
5 0000000000000000000000000000000000000000000000000000000000000000000000 
6 0000000000000000000000000000000000000000000000000000000000000000000000 
7 0000000000000000000000000000000000000000000000000000000000000000000000 
8 0000000000000000000000000000000000000000000000000000000000000000000000 
9 0000000000000000000000000000000000000000000000000000000000000000000000 
10 0000000000000000000000000000000000000000000000000000000000000000000000 
11 0000000000000000000000000000000000000000000000000000000000000000000000 
12 0000000000000000000000000000000000000000000000000000000000000000000000 
13 0000000000000000000000000000000000000000000000000000000000000000000000 
14 0000000000000000000000000000000000000000000000000000000000000000000000 
15 0000000000000000000000000000000000000000000000000000000000000000000000 
16 0000000000000000000000000000000000000000000000000000000000000000000000 
17 0000000000000000000000000000000000000000000000000000000000000000000000 
18 0000000000000000000000000000000000000000000000000000000000000000000000 
19 0000000000000000000000000000000000000000000000000000000000000000000000 
20 0000000000000000000000000000000000000000000000000000000000000000000000 
21 0000000000000000000000000000000000000000000000000000000000000000000000 
22 0000000000000000000000000000000000000000000000000000000000000000000000 
23 0000000000000000000000000000000000000000000000000000000000000000000000 
24 0000000000000000000000000000000000000000000000000000000000000000000000 
25 0000000000000000000000000000000000000000000000000000000000000000000000 
26 0000000000000000000000000000000000000000000000000000000000000000000000 
27 0000000000000000000000000000000000000000000000000000000000000000000000 
28 0000000000000000000000000000000000000000000000000000000000000000000000 
29 000000000000000000000000000000000000000000 
  
30 Key·0x7109871a: 
31 f7050000f3050000b50300002c00000028000000030100002000000079e4450ba1925f 
32 14838eaf4d8e28d350f4ac895d4f89aad38e69ed608a5af8236d030000690300003082 
33 03653082024da003020102020863707fe532bb2ae7300d06092a864886f70d01010b05 
34 003060310b300906035504061302554b310c300a060355040813034f5247310c300a06 
35 0355040713034f524731133011060355040a130a6664726f69642e6f7267310f300d06 
36 0355040b13064644726f6964310f300d060355040313064644726f69643020170d3236 
37 303632373135343331325a180f32303533313131323135343331325a3060310b300906 
38 035504061302554b310c300a060355040813034f5247310c300a060355040713034f52 
39 4731133011060355040a130a6664726f69642e6f7267310f300d060355040b13064644 
40 726f6964310f300d060355040313064644726f696430820122300d06092a864886f70d 
41 01010105000382010f003082010a0282010100ac74a8f4fb5ff9c1a0338278598eb9c6 
42 ba0fce0774e5f2dfe7d8aff70c0cb2535a834e125f1581127f7a6f5d3f86dc5195fd7a 
43 4b1c92b26bd6422d7d34de63f255b1782446868cb7bfdc3b992ccb233a52ef9c4d5f81 
44 954926ca92954b14f8046ec50a095dd5556832565712fd9d41cd934410056864573af7 
45 d8187d1774c6a004b928eb712a907ec5944e75acd901cfb09a1ce230815caae69da3a0 
46 b6bf6fb6d63156b21b8922ed1917331c4f1421eaa8dbb232f7832dcc35e7a6e6907f62 
47 df44fe4a73cd3f238002dfc7a5e2e2fc64ce1596966c7c411f63ad2e19c0339354c530 
48 83b31e8cfb923799d505bbaa8c2d6bf92187fe3ae13fe30eabe346242d110203010001 
49 a321301f301d0603551d0e04160414ecb0d0226aa2fe884f4897c348146f3ffffc96b7 
50 300d06092a864886f70d01010b0500038201010048373d1fdd119f7858e6e3c2e5c181 
51 b3ed8072b53c4ab90889efb9b8cd0c23eab3e01752c48305ee01f073d5a108e62196d4 
52 ce553bb0022a0055cac40979bccc03c1a6c90ee4baaad9f217f746731470b128bfd3b2 
53 4d67879509be45a91d5042396036d3b05594d1f5055dca470801751296b3c5f4d72ece 
54 c04320cbbb69ee8a6d9d39309916850db9939afdfca7c90755c57a88fe82343d2b02cb 
55 fa45c1467ddc6e81e59fadd39925d9b2e62e85c55625247f04ce42a115ae52a52dec25 
56 f249cf08a392f7efb473a319ea4e410e74bb516475b7c881610fb95a013a9209c4243c 
57 948166bff03e2a50f4c1e6da3bad7c6a918afeeb7472bc45ad09efe63b47200c000000 
58 080000000df0efbe03000000000000000c0100000801000003010000000100008a8ba5 
59 327ccfe9eb8a1fc412bc3aab3709dea78d88004af840290a192951e082a723b90abc98 
60 5cbc35a27a58b02eb935831b35be0e4a5acd42e656049b94f2674f843c34a86aeef731 
61 29185621e250b6c9a7c850af7be0dc32f6e800e9a2018cc1b228ab91d201c130d7c0fa 
62 c768580ee93fecb41f909378db00720d66cd7cda40221d8631e307153d1d696f2fedbb 
63 6240b75c39409387770028b29b286a2c53c4bc985716d72da536b0a1398cd5bfa5bcef 
64 93aaab6df7903008a4911d1966737af7870d931c582364d080d0fbcda3c0b2ee3c9f7f 
65 13f2785a68f8e6406f0f14673fd34293a7a25274bd6ffc82baca468c32d247a9eca84e 
66 9c8203aaf937c82f2601000030820122300d06092a864886f70d01010105000382010f 
67 003082010a0282010100ac74a8f4fb5ff9c1a0338278598eb9c6ba0fce0774e5f2dfe7 
68 d8aff70c0cb2535a834e125f1581127f7a6f5d3f86dc5195fd7a4b1c92b26bd6422d7d 
69 34de63f255b1782446868cb7bfdc3b992ccb233a52ef9c4d5f81954926ca92954b14f8 
70 046ec50a095dd5556832565712fd9d41cd934410056864573af7d8187d1774c6a004b9 
71 28eb712a907ec5944e75acd901cfb09a1ce230815caae69da3a0b6bf6fb6d63156b21b 
72 8922ed1917331c4f1421eaa8dbb232f7832dcc35e7a6e6907f62df44fe4a73cd3f2380 
73 02dfc7a5e2e2fc64ce1596966c7c411f63ad2e19c0339354c53083b31e8cfb923799d5 
74 05bbaa8c2d6bf92187fe3ae13fe30eabe346242d110203010001 
  
75 Key·0xf05368c0: 
76 f7050000f3050000ad0300002c00000028000000030100002000000079e4450ba1925f 
77 14838eaf4d8e28d350f4ac895d4f89aad38e69ed608a5af8236d030000690300003082 
78 03653082024da003020102020863707fe532bb2ae7300d06092a864886f70d01010b05 
79 003060310b300906035504061302554b310c300a060355040813034f5247310c300a06 
80 0355040713034f524731133011060355040a130a6664726f69642e6f7267310f300d06 
81 0355040b13064644726f6964310f300d060355040313064644726f69643020170d3236 
82 303632373135343331325a180f32303533313131323135343331325a3060310b300906 
83 035504061302554b310c300a060355040813034f5247310c300a060355040713034f52 
84 4731133011060355040a130a6664726f69642e6f7267310f300d060355040b13064644 
85 726f6964310f300d060355040313064644726f696430820122300d06092a864886f70d 
86 01010105000382010f003082010a0282010100ac74a8f4fb5ff9c1a0338278598eb9c6 
87 ba0fce0774e5f2dfe7d8aff70c0cb2535a834e125f1581127f7a6f5d3f86dc5195fd7a 
88 4b1c92b26bd6422d7d34de63f255b1782446868cb7bfdc3b992ccb233a52ef9c4d5f81 
89 954926ca92954b14f8046ec50a095dd5556832565712fd9d41cd934410056864573af7 
90 d8187d1774c6a004b928eb712a907ec5944e75acd901cfb09a1ce230815caae69da3a0 
91 b6bf6fb6d63156b21b8922ed1917331c4f1421eaa8dbb232f7832dcc35e7a6e6907f62 
92 df44fe4a73cd3f238002dfc7a5e2e2fc64ce1596966c7c411f63ad2e19c0339354c530 
93 83b31e8cfb923799d505bbaa8c2d6bf92187fe3ae13fe30eabe346242d110203010001 
94 a321301f301d0603551d0e04160414ecb0d0226aa2fe884f4897c348146f3ffffc96b7 
95 300d06092a864886f70d01010b0500038201010048373d1fdd119f7858e6e3c2e5c181 
96 b3ed8072b53c4ab90889efb9b8cd0c23eab3e01752c48305ee01f073d5a108e62196d4 
97 ce553bb0022a0055cac40979bccc03c1a6c90ee4baaad9f217f746731470b128bfd3b2 
98 4d67879509be45a91d5042396036d3b05594d1f5055dca470801751296b3c5f4d72ece 
99 c04320cbbb69ee8a6d9d39309916850db9939afdfca7c90755c57a88fe82343d2b02cb 
100 fa45c1467ddc6e81e59fadd39925d9b2e62e85c55625247f04ce42a115ae52a52dec25 
101 f249cf08a392f7efb473a319ea4e410e74bb516475b7c881610fb95a013a9209c4243c 
102 948166bff03e2a50f4c1e6da3bad7c6a918afeeb7472bc45ad09efe63b472018000000 
103 ffffff7f0000000018000000ffffff7f0c01000008010000030100000001000000d108 
104 ce8610437b20888ed3f752b7cede7790989f002b065d2a6e027150538ef2de15c8c198 
105 f3fbbb1756799e80bf8cebc14f955a7246df7b276b3a31e8b2373d70c261bd0ea7eb48 
106 22009b54cce3cd4d0865aff9ba74dfc24a5ba0aa4cbc8bf83078819f42693a211c59a5 
107 a6e9a3063bd6be891b7ba065b96fe2762a19fa281e6b7be61925455f0ab03939af8e8c 
108 e4c8f17b419578e88e232467256c052e5c3db9ae2adfe708297dc93cdea10b76a49bd0 
109 817d4d84759e04208fecee8a2758dc31f07b1e1163b26948b6fc050b291a9bc973d054 
110 084910a92f89039d2b6fa93957a9a1a191c02c7fbb79e1c2ba6da0b69273ba678eae73 
111 fd54897bd3cb23022601000030820122300d06092a864886f70d01010105000382010f 
112 003082010a0282010100ac74a8f4fb5ff9c1a0338278598eb9c6ba0fce0774e5f2dfe7 
113 d8aff70c0cb2535a834e125f1581127f7a6f5d3f86dc5195fd7a4b1c92b26bd6422d7d 
114 34de63f255b1782446868cb7bfdc3b992ccb233a52ef9c4d5f81954926ca92954b14f8 
115 046ec50a095dd5556832565712fd9d41cd934410056864573af7d8187d1774c6a004b9 
116 28eb712a907ec5944e75acd901cfb09a1ce230815caae69da3a0b6bf6fb6d63156b21b 
117 8922ed1917331c4f1421eaa8dbb232f7832dcc35e7a6e6907f62df44fe4a73cd3f2380 
118 02dfc7a5e2e2fc64ce1596966c7c411f63ad2e19c0339354c53083b31e8cfb923799d5 
119 05bbaa8c2d6bf92187fe3ae13fe30eabe346242d110203010001 
⊟
3.02 KB
zipinfo {}
    
Offset 1, 8 lines modifiedOffset 1, 8 lines modified
1 Zip·file·size:·63374044·bytes,·number·of·entries:·2181 Zip·file·size:·63398005·bytes,·number·of·entries:·215
2 -rw-r--r--··0.0·unx·······56·b-·defN·81-Jan-01·01:01·META-INF/com/android/build/gradle/app-metadata.properties2 -rw-r--r--··0.0·unx·······56·b-·defN·81-Jan-01·01:01·META-INF/com/android/build/gradle/app-metadata.properties
3 -rw-r--r--··0.0·unx······120·b-·defN·81-Jan-01·01:01·META-INF/version-control-info.textproto3 -rw-r--r--··0.0·unx······120·b-·defN·81-Jan-01·01:01·META-INF/version-control-info.textproto
4 -rw-r--r--··0.0·unx·····6978·b-·stor·81-Jan-01·01:01·assets/dexopt/baseline.prof4 -rw-r--r--··0.0·unx·····6978·b-·stor·81-Jan-01·01:01·assets/dexopt/baseline.prof
5 -rw-r--r--··0.0·unx······391·b-·stor·81-Jan-01·01:01·assets/dexopt/baseline.profm5 -rw-r--r--··0.0·unx······391·b-·stor·81-Jan-01·01:01·assets/dexopt/baseline.profm
6 -rw-r--r--··0.0·unx·13583992·b-·defN·81-Jan-01·01:01·classes.dex6 -rw-r--r--··0.0·unx·13583992·b-·defN·81-Jan-01·01:01·classes.dex
7 -rw-r--r--··0.0·unx··4070252·b-·defN·81-Jan-01·01:01·classes2.dex7 -rw-r--r--··0.0·unx··4070252·b-·defN·81-Jan-01·01:01·classes2.dex
8 -rw-r--r--··0.0·unx····10096·b-·stor·81-Jan-01·01:01·lib/arm64-v8a/libandroidx.graphics.path.so8 -rw-r--r--··0.0·unx····10096·b-·stor·81-Jan-01·01:01·lib/arm64-v8a/libandroidx.graphics.path.so
Offset 70, 15 lines modifiedOffset 70, 15 lines modified
70 -rw-r--r--··0.0·unx····24336·b-·stor·81-Jan-01·01:01·assets/chaquopy/bootstrap-native/x86_64/mmap.so70 -rw-r--r--··0.0·unx····24336·b-·stor·81-Jan-01·01:01·assets/chaquopy/bootstrap-native/x86_64/mmap.so
71 -rw-r--r--··0.0·unx····37608·b-·stor·81-Jan-01·01:01·assets/chaquopy/bootstrap-native/x86_64/zlib.so71 -rw-r--r--··0.0·unx····37608·b-·stor·81-Jan-01·01:01·assets/chaquopy/bootstrap-native/x86_64/zlib.so
72 -rw-r--r--··0.0·unx···624933·b-·stor·81-Jan-01·01:01·assets/chaquopy/bootstrap.imy72 -rw-r--r--··0.0·unx···624933·b-·stor·81-Jan-01·01:01·assets/chaquopy/bootstrap.imy
73 -rw-r--r--··0.0·unx·····4242·b-·defN·81-Jan-01·01:01·assets/chaquopy/build.json73 -rw-r--r--··0.0·unx·····4242·b-·defN·81-Jan-01·01:01·assets/chaquopy/build.json
74 -rw-r--r--··0.0·unx···299427·b-·defN·81-Jan-01·01:01·assets/chaquopy/cacert.pem74 -rw-r--r--··0.0·unx···299427·b-·defN·81-Jan-01·01:01·assets/chaquopy/cacert.pem
75 -rw-r--r--··0.0·unx··2594339·b-·stor·81-Jan-01·01:01·assets/chaquopy/requirements-arm64-v8a.imy75 -rw-r--r--··0.0·unx··2594339·b-·stor·81-Jan-01·01:01·assets/chaquopy/requirements-arm64-v8a.imy
76 -rw-r--r--··0.0·unx··2315511·b-·stor·81-Jan-01·01:01·assets/chaquopy/requirements-armeabi-v7a.imy76 -rw-r--r--··0.0·unx··2315511·b-·stor·81-Jan-01·01:01·assets/chaquopy/requirements-armeabi-v7a.imy
77 -rw-r--r--··0.0·unx··3734889·b-·stor·81-Jan-01·01:01·assets/chaquopy/requirements-common.imy77 -rw-r--r--··0.0·unx··3780927·b-·stor·81-Jan-01·01:01·assets/chaquopy/requirements-common.imy
78 -rw-r--r--··0.0·unx··2725620·b-·stor·81-Jan-01·01:01·assets/chaquopy/requirements-x86_64.imy78 -rw-r--r--··0.0·unx··2725620·b-·stor·81-Jan-01·01:01·assets/chaquopy/requirements-x86_64.imy
79 -rw-r--r--··0.0·unx··1478595·b-·stor·81-Jan-01·01:01·assets/chaquopy/stdlib-arm64-v8a.imy79 -rw-r--r--··0.0·unx··1478595·b-·stor·81-Jan-01·01:01·assets/chaquopy/stdlib-arm64-v8a.imy
80 -rw-r--r--··0.0·unx··1386480·b-·stor·81-Jan-01·01:01·assets/chaquopy/stdlib-armeabi-v7a.imy80 -rw-r--r--··0.0·unx··1386480·b-·stor·81-Jan-01·01:01·assets/chaquopy/stdlib-armeabi-v7a.imy
81 -rw-r--r--··0.0·unx··4812526·b-·stor·81-Jan-01·01:01·assets/chaquopy/stdlib-common.imy81 -rw-r--r--··0.0·unx··4812526·b-·stor·81-Jan-01·01:01·assets/chaquopy/stdlib-common.imy
82 -rw-r--r--··0.0·unx··1508233·b-·stor·81-Jan-01·01:01·assets/chaquopy/stdlib-x86_64.imy82 -rw-r--r--··0.0·unx··1508233·b-·stor·81-Jan-01·01:01·assets/chaquopy/stdlib-x86_64.imy
83 -rw----·····2.4·fat·····1738·b-·defN·81-Jan-01·01:01·DebugProbesKt.bin83 -rw----·····2.4·fat·····1738·b-·defN·81-Jan-01·01:01·DebugProbesKt.bin
84 -rw----·····2.4·fat········6·b-·stor·81-Jan-01·01:01·META-INF/androidx.activity_activity-compose.version84 -rw----·····2.4·fat········6·b-·stor·81-Jan-01·01:01·META-INF/androidx.activity_activity-compose.version
Offset 210, 11 lines modifiedOffset 210, 8 lines modified
210 -rw----·····0.0·fat······225·b-·stor·81-Jan-01·01:01·res/wN.9.png210 -rw----·····0.0·fat······225·b-·stor·81-Jan-01·01:01·res/wN.9.png
211 -rw----·····0.0·fat·····2456·b-·defN·81-Jan-01·01:01·res/xN.xml211 -rw----·····0.0·fat·····2456·b-·defN·81-Jan-01·01:01·res/xN.xml
212 -rw----·····0.0·fat······221·b-·stor·81-Jan-01·01:01·res/xa.9.png212 -rw----·····0.0·fat······221·b-·stor·81-Jan-01·01:01·res/xa.9.png
213 -rw----·····0.0·fat······221·b-·stor·81-Jan-01·01:01·res/z-.9.png213 -rw----·····0.0·fat······221·b-·stor·81-Jan-01·01:01·res/z-.9.png
214 -rw----·····0.0·fat······206·b-·stor·81-Jan-01·01:01·res/zL.png214 -rw----·····0.0·fat······206·b-·stor·81-Jan-01·01:01·res/zL.png
215 -rw----·····0.0·fat······884·b-·stor·81-Jan-01·01:01·res/zz.png215 -rw----·····0.0·fat······884·b-·stor·81-Jan-01·01:01·res/zz.png
216 -rw----·····0.0·fat···415976·b-·stor·81-Jan-01·01:01·resources.arsc216 -rw----·····0.0·fat···415976·b-·stor·81-Jan-01·01:01·resources.arsc
217 -rw----·····2.0·fat····22646·b-·defN·81-Jan-01·01:01·META-INF/57818ACA.SF 
218 -rw----·····2.0·fat·····1344·b-·defN·81-Jan-01·01:01·META-INF/57818ACA.RSA 
219 -rw----·····2.0·fat····22519·b-·defN·81-Jan-01·01:01·META-INF/MANIFEST.MF 
220 218·files,·74758203·bytes·uncompressed,·62848482·bytes·compressed:··15.9%217 215·files,·74757732·bytes·uncompressed,·62876922·bytes·compressed:··15.9%
⊟
3.51 MB
assets/chaquopy/requirements-common.imy
⊟
25.8 KB
zipinfo {}
    
Offset 1, 8 lines modifiedOffset 1, 8 lines modified
1 Zip·file·size:·3734889·bytes,·number·of·entries:·7731 Zip·file·size:·3780927·bytes,·number·of·entries:·772
2 -rw----·····2.0·fat····34703·b-·defN·80-Feb-01·00:00·six.py2 -rw----·····2.0·fat····34703·b-·defN·80-Feb-01·00:00·six.py
3 -rw----·····2.0·fat···165012·b-·defN·80-Feb-01·00:00·typing_extensions.py3 -rw----·····2.0·fat···165012·b-·defN·80-Feb-01·00:00·typing_extensions.py
4 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·PIL/4 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·PIL/
5 -rw----·····2.0·fat·····3477·b-·defN·80-Feb-01·00:00·PIL/BdfFontFile.py5 -rw----·····2.0·fat·····3477·b-·defN·80-Feb-01·00:00·PIL/BdfFontFile.py
6 -rw----·····2.0·fat····16584·b-·defN·80-Feb-01·00:00·PIL/BlpImagePlugin.py6 -rw----·····2.0·fat····16584·b-·defN·80-Feb-01·00:00·PIL/BlpImagePlugin.py
7 -rw----·····2.0·fat····19758·b-·defN·80-Feb-01·00:00·PIL/BmpImagePlugin.py7 -rw----·····2.0·fat····19758·b-·defN·80-Feb-01·00:00·PIL/BmpImagePlugin.py
8 -rw----·····2.0·fat·····1753·b-·defN·80-Feb-01·00:00·PIL/BufrStubImagePlugin.py8 -rw----·····2.0·fat·····1753·b-·defN·80-Feb-01·00:00·PIL/BufrStubImagePlugin.py
Offset 142, 35 lines modifiedOffset 142, 35 lines modified
142 -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·chaquopy_libxml2-2.9.8.dist-info/INSTALLER142 -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·chaquopy_libxml2-2.9.8.dist-info/INSTALLER
143 -rw----·····2.0·fat·······86·b-·defN·80-Feb-01·00:00·chaquopy_libxml2-2.9.8.dist-info/METADATA143 -rw----·····2.0·fat·······86·b-·defN·80-Feb-01·00:00·chaquopy_libxml2-2.9.8.dist-info/METADATA
144 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·chaquopy_libxslt-1.1.32.dist-info/144 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·chaquopy_libxslt-1.1.32.dist-info/
145 -rw----·····2.0·fat·····2968·b-·defN·80-Feb-01·00:00·chaquopy_libxslt-1.1.32.dist-info/COPYING145 -rw----·····2.0·fat·····2968·b-·defN·80-Feb-01·00:00·chaquopy_libxslt-1.1.32.dist-info/COPYING
146 -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·chaquopy_libxslt-1.1.32.dist-info/INSTALLER146 -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·chaquopy_libxslt-1.1.32.dist-info/INSTALLER
147 -rw----·····2.0·fat······129·b-·defN·80-Feb-01·00:00·chaquopy_libxslt-1.1.32.dist-info/METADATA147 -rw----·····2.0·fat······129·b-·defN·80-Feb-01·00:00·chaquopy_libxslt-1.1.32.dist-info/METADATA
148 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·charset_normalizer/148 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·charset_normalizer/
149 -rw----·····2.0·fat·····1590·b-·defN·80-Feb-01·00:00·charset_normalizer/__init__.py149 -rw----·····2.0·fat·····1582·b-·defN·80-Feb-01·00:00·charset_normalizer/__init__.py
150 -rw----·····2.0·fat······109·b-·defN·80-Feb-01·00:00·charset_normalizer/__main__.py150 -rw----·····2.0·fat······109·b-·defN·80-Feb-01·00:00·charset_normalizer/__main__.py
151 -rw----·····2.0·fat····42325·b-·defN·80-Feb-01·00:00·charset_normalizer/api.py151 -rw----·····2.0·fat····35774·b-·defN·80-Feb-01·00:00·charset_normalizer/api.py
152 -rw----·····2.0·fat····15980·b-·defN·80-Feb-01·00:00·charset_normalizer/cd.py152 -rw----·····2.0·fat····15980·b-·defN·80-Feb-01·00:00·charset_normalizer/cd.py
153 -rw----·····2.0·fat····44624·b-·defN·80-Feb-01·00:00·charset_normalizer/constant.py153 -rw----·····2.0·fat····60812·b-·defN·80-Feb-01·00:00·charset_normalizer/constant.py
154 -rw----·····2.0·fat·····2651·b-·defN·80-Feb-01·00:00·charset_normalizer/legacy.py154 -rw----·····2.0·fat·····2651·b-·defN·80-Feb-01·00:00·charset_normalizer/legacy.py
155 -rw----·····2.0·fat····32641·b-·defN·80-Feb-01·00:00·charset_normalizer/md.py155 -rw----·····2.0·fat····35274·b-·defN·80-Feb-01·00:00·charset_normalizer/md.py
156 -rw----·····2.0·fat····12830·b-·defN·80-Feb-01·00:00·charset_normalizer/models.py156 -rw----·····2.0·fat····13530·b-·defN·80-Feb-01·00:00·charset_normalizer/models.py
157 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·charset_normalizer/py.typed157 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·charset_normalizer/py.typed
158 -rw----·····2.0·fat····13537·b-·defN·80-Feb-01·00:00·charset_normalizer/utils.py158 -rw----·····2.0·fat····14122·b-·defN·80-Feb-01·00:00·charset_normalizer/utils.py
159 -rw----·····2.0·fat······115·b-·defN·80-Feb-01·00:00·charset_normalizer/version.py159 -rw----·····2.0·fat······115·b-·defN·80-Feb-01·00:00·charset_normalizer/version.py
160 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·charset_normalizer/cli/160 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·charset_normalizer/cli/
161 -rw----·····2.0·fat······136·b-·defN·80-Feb-01·00:00·charset_normalizer/cli/__init__.py161 -rw----·····2.0·fat······136·b-·defN·80-Feb-01·00:00·charset_normalizer/cli/__init__.py
162 -rw----·····2.0·fat····11949·b-·defN·80-Feb-01·00:00·charset_normalizer/cli/__main__.py162 -rw----·····2.0·fat····11949·b-·defN·80-Feb-01·00:00·charset_normalizer/cli/__main__.py
163 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·charset_normalizer-3.4.9.dist-info/163 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·charset_normalizer-3.5.2.dist-info/
164 -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·charset_normalizer-3.4.9.dist-info/INSTALLER164 -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·charset_normalizer-3.5.2.dist-info/INSTALLER
165 -rw----·····2.0·fat····41678·b-·defN·80-Feb-01·00:00·charset_normalizer-3.4.9.dist-info/METADATA165 -rw----·····2.0·fat····46395·b-·defN·80-Feb-01·00:00·charset_normalizer-3.5.2.dist-info/METADATA
166 -rw----·····2.0·fat·······65·b-·defN·80-Feb-01·00:00·charset_normalizer-3.4.9.dist-info/entry_points.txt166 -rw----·····2.0·fat·······65·b-·defN·80-Feb-01·00:00·charset_normalizer-3.5.2.dist-info/entry_points.txt
167 -rw----·····2.0·fat·······19·b-·defN·80-Feb-01·00:00·charset_normalizer-3.4.9.dist-info/top_level.txt167 -rw----·····2.0·fat·······19·b-·defN·80-Feb-01·00:00·charset_normalizer-3.5.2.dist-info/top_level.txt
168 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·charset_normalizer-3.4.9.dist-info/licenses/168 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·charset_normalizer-3.5.2.dist-info/licenses/
169 -rw----·····2.0·fat·····1071·b-·defN·80-Feb-01·00:00·charset_normalizer-3.4.9.dist-info/licenses/LICENSE169 -rw----·····2.0·fat·····1071·b-·defN·80-Feb-01·00:00·charset_normalizer-3.5.2.dist-info/licenses/LICENSE
170 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·css_parser/170 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·css_parser/
171 -rw----·····2.0·fat····15860·b-·defN·80-Feb-01·00:00·css_parser/__init__.py171 -rw----·····2.0·fat····15860·b-·defN·80-Feb-01·00:00·css_parser/__init__.py
172 -rw----·····2.0·fat·····1891·b-·defN·80-Feb-01·00:00·css_parser/_fetch.py172 -rw----·····2.0·fat·····1891·b-·defN·80-Feb-01·00:00·css_parser/_fetch.py
173 -rw----·····2.0·fat·····2715·b-·defN·80-Feb-01·00:00·css_parser/_fetchgae.py173 -rw----·····2.0·fat·····2715·b-·defN·80-Feb-01·00:00·css_parser/_fetchgae.py
174 -rw----·····2.0·fat····24413·b-·defN·80-Feb-01·00:00·css_parser/codec.py174 -rw----·····2.0·fat····24413·b-·defN·80-Feb-01·00:00·css_parser/codec.py
175 -rw----·····2.0·fat·····4929·b-·defN·80-Feb-01·00:00·css_parser/cssproductions.py175 -rw----·····2.0·fat·····4929·b-·defN·80-Feb-01·00:00·css_parser/cssproductions.py
176 -rw----·····2.0·fat·····4059·b-·defN·80-Feb-01·00:00·css_parser/errorhandler.py176 -rw----·····2.0·fat·····4059·b-·defN·80-Feb-01·00:00·css_parser/errorhandler.py
Offset 226, 23 lines modifiedOffset 226, 23 lines modified
226 -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·css_parser-1.1.1.dist-info/INSTALLER226 -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·css_parser-1.1.1.dist-info/INSTALLER
227 -rw----·····2.0·fat·····1582·b-·defN·80-Feb-01·00:00·css_parser-1.1.1.dist-info/METADATA227 -rw----·····2.0·fat·····1582·b-·defN·80-Feb-01·00:00·css_parser-1.1.1.dist-info/METADATA
228 -rw----·····2.0·fat·······11·b-·defN·80-Feb-01·00:00·css_parser-1.1.1.dist-info/top_level.txt228 -rw----·····2.0·fat·······11·b-·defN·80-Feb-01·00:00·css_parser-1.1.1.dist-info/top_level.txt
229 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·css_parser-1.1.1.dist-info/licenses/229 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·css_parser-1.1.1.dist-info/licenses/
230 -rw----·····2.0·fat····35821·b-·defN·80-Feb-01·00:00·css_parser-1.1.1.dist-info/licenses/COPYING230 -rw----·····2.0·fat····35821·b-·defN·80-Feb-01·00:00·css_parser-1.1.1.dist-info/licenses/COPYING
231 -rw----·····2.0·fat·····7802·b-·defN·80-Feb-01·00:00·css_parser-1.1.1.dist-info/licenses/COPYING.LESSER231 -rw----·····2.0·fat·····7802·b-·defN·80-Feb-01·00:00·css_parser-1.1.1.dist-info/licenses/COPYING.LESSER
232 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·cssselect2/232 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·cssselect2/
233 -rw----·····2.0·fat·····4289·b-·defN·80-Feb-01·00:00·cssselect2/__init__.py233 -rw----·····2.0·fat·····4290·b-·defN·80-Feb-01·00:00·cssselect2/__init__.py
234 -rw----·····2.0·fat····18907·b-·defN·80-Feb-01·00:00·cssselect2/compiler.py234 -rw----·····2.0·fat····18907·b-·defN·80-Feb-01·00:00·cssselect2/compiler.py
235 -rw----·····2.0·fat····16285·b-·defN·80-Feb-01·00:00·cssselect2/parser.py235 -rw----·····2.0·fat····16357·b-·defN·80-Feb-01·00:00·cssselect2/parser.py
236 -rw----·····2.0·fat····13612·b-·defN·80-Feb-01·00:00·cssselect2/tree.py236 -rw----·····2.0·fat····13612·b-·defN·80-Feb-01·00:00·cssselect2/tree.py
237 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·cssselect2-0.9.0.dist-info/237 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·cssselect2-0.10.1.dist-info/
238 -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·cssselect2-0.9.0.dist-info/INSTALLER238 -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·cssselect2-0.10.1.dist-info/INSTALLER
239 -rw----·····2.0·fat·····2916·b-·defN·80-Feb-01·00:00·cssselect2-0.9.0.dist-info/METADATA239 -rw----·····2.0·fat·····2941·b-·defN·80-Feb-01·00:00·cssselect2-0.10.1.dist-info/METADATA
240 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·cssselect2-0.9.0.dist-info/licenses/240 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·cssselect2-0.10.1.dist-info/licenses/
241 -rw----·····2.0·fat·····1548·b-·defN·80-Feb-01·00:00·cssselect2-0.9.0.dist-info/licenses/LICENSE241 -rw----·····2.0·fat·····1548·b-·defN·80-Feb-01·00:00·cssselect2-0.10.1.dist-info/licenses/LICENSE
242 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·dateutil/242 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·dateutil/
243 -rw----·····2.0·fat······620·b-·defN·80-Feb-01·00:00·dateutil/__init__.py243 -rw----·····2.0·fat······620·b-·defN·80-Feb-01·00:00·dateutil/__init__.py
244 -rw----·····2.0·fat······932·b-·defN·80-Feb-01·00:00·dateutil/_common.py244 -rw----·····2.0·fat······932·b-·defN·80-Feb-01·00:00·dateutil/_common.py
245 -rw----·····2.0·fat······166·b-·defN·80-Feb-01·00:00·dateutil/_version.py245 -rw----·····2.0·fat······166·b-·defN·80-Feb-01·00:00·dateutil/_version.py
246 -rw----·····2.0·fat·····2678·b-·defN·80-Feb-01·00:00·dateutil/easter.py246 -rw----·····2.0·fat·····2678·b-·defN·80-Feb-01·00:00·dateutil/easter.py
247 -rw----·····2.0·fat····24903·b-·defN·80-Feb-01·00:00·dateutil/relativedelta.py247 -rw----·····2.0·fat····24903·b-·defN·80-Feb-01·00:00·dateutil/relativedelta.py
248 -rw----·····2.0·fat····66557·b-·defN·80-Feb-01·00:00·dateutil/rrule.py248 -rw----·····2.0·fat····66557·b-·defN·80-Feb-01·00:00·dateutil/rrule.py
Offset 276, 42 lines modifiedOffset 276, 44 lines modified
276 -rw----·····2.0·fat·····5364·b-·defN·80-Feb-01·00:00·defusedxml/xmlrpc.py276 -rw----·····2.0·fat·····5364·b-·defN·80-Feb-01·00:00·defusedxml/xmlrpc.py
277 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·defusedxml-0.7.1.dist-info/277 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·defusedxml-0.7.1.dist-info/
278 -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·defusedxml-0.7.1.dist-info/INSTALLER278 -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·defusedxml-0.7.1.dist-info/INSTALLER
279 -rw----·····2.0·fat·····2409·b-·defN·80-Feb-01·00:00·defusedxml-0.7.1.dist-info/LICENSE279 -rw----·····2.0·fat·····2409·b-·defN·80-Feb-01·00:00·defusedxml-0.7.1.dist-info/LICENSE
280 -rw----·····2.0·fat····32518·b-·defN·80-Feb-01·00:00·defusedxml-0.7.1.dist-info/METADATA280 -rw----·····2.0·fat····32518·b-·defN·80-Feb-01·00:00·defusedxml-0.7.1.dist-info/METADATA
281 -rw----·····2.0·fat·······11·b-·defN·80-Feb-01·00:00·defusedxml-0.7.1.dist-info/top_level.txt281 -rw----·····2.0·fat·······11·b-·defN·80-Feb-01·00:00·defusedxml-0.7.1.dist-info/top_level.txt
282 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·filelock/282 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·filelock/
283 -rw----·····2.0·fat·····3469·b-·defN·80-Feb-01·00:00·filelock/__init__.py283 -rw----·····2.0·fat·····3996·b-·defN·80-Feb-01·00:00·filelock/__init__.py
284 -rw----·····2.0·fat····82263·b-·defN·80-Feb-01·00:00·filelock/_api.py284 -rw----·····2.0·fat····97553·b-·defN·80-Feb-01·00:00·filelock/_api.py
285 -rw----·····2.0·fat·····5209·b-·defN·80-Feb-01·00:00·filelock/_async.py285 -rw----·····2.0·fat····14188·b-·defN·80-Feb-01·00:00·filelock/_async.py
286 -rw----·····2.0·fat····13971·b-·defN·80-Feb-01·00:00·filelock/_async_read_write.py286 -rw----·····2.0·fat····14563·b-·defN·80-Feb-01·00:00·filelock/_async_read_write.py
287 -rw----·····2.0·fat·····2981·b-·defN·80-Feb-01·00:00·filelock/_descriptor.py287 -rw----·····2.0·fat·····3191·b-·defN·80-Feb-01·00:00·filelock/_descriptor.py
288 -rw----·····2.0·fat·····2699·b-·defN·80-Feb-01·00:00·filelock/_error.py288 -rw----·····2.0·fat·····3204·b-·defN·80-Feb-01·00:00·filelock/_error.py
289 -rw----·····2.0·fat·····8415·b-·defN·80-Feb-01·00:00·filelock/_identity.py289 -rw----·····2.0·fat····14275·b-·defN·80-Feb-01·00:00·filelock/_identity.py
290 -rw----·····2.0·fat····14547·b-·defN·80-Feb-01·00:00·filelock/_lease.py290 -rw----·····2.0·fat····17965·b-·defN·80-Feb-01·00:00·filelock/_lease.py
291 -rw----·····2.0·fat·····6026·b-·defN·80-Feb-01·00:00·filelock/_marker.py291 -rw----·····2.0·fat·····7164·b-·defN·80-Feb-01·00:00·filelock/_marker.py
292 -rw----·····2.0·fat····32895·b-·defN·80-Feb-01·00:00·filelock/_read_write.py292 -rw----·····2.0·fat····52720·b-·defN·80-Feb-01·00:00·filelock/_read_write.py
293 -rw----·····2.0·fat····13014·b-·defN·80-Feb-01·00:00·filelock/_soft.py293 -rw----·····2.0·fat····19410·b-·defN·80-Feb-01·00:00·filelock/_soft.py
294 -rw----·····2.0·fat······187·b-·defN·80-Feb-01·00:00·filelock/_soft_protocol.py294 -rw----·····2.0·fat······187·b-·defN·80-Feb-01·00:00·filelock/_soft_protocol.py
295 -rw----·····2.0·fat····38823·b-·defN·80-Feb-01·00:00·filelock/_strict.py295 -rw----·····2.0·fat····47830·b-·defN·80-Feb-01·00:00·filelock/_strict.py
296 -rw----·····2.0·fat·····8722·b-·defN·80-Feb-01·00:00·filelock/_unix.py296 -rw----·····2.0·fat·····9220·b-·defN·80-Feb-01·00:00·filelock/_unix.py
297 -rw----·····2.0·fat·····6356·b-·defN·80-Feb-01·00:00·filelock/_util.py297 -rw----·····2.0·fat·····7404·b-·defN·80-Feb-01·00:00·filelock/_util.py
298 -rw----·····2.0·fat····15988·b-·defN·80-Feb-01·00:00·filelock/_windows.py298 -rw----·····2.0·fat····17033·b-·defN·80-Feb-01·00:00·filelock/_windows.py
299 -rw----·····2.0·fat····34599·b-·defN·80-Feb-01·00:00·filelock/asyncio.py299 -rw----·····2.0·fat····41361·b-·defN·80-Feb-01·00:00·filelock/asyncio.py
300 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·filelock/py.typed300 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·filelock/py.typed
301 -rw----·····2.0·fat······522·b-·defN·80-Feb-01·00:00·filelock/version.py301 -rw----·····2.0·fat······520·b-·defN·80-Feb-01·00:00·filelock/version.py
302 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·filelock/_soft_rw/302 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·filelock/_soft_rw/
303 -rw----·····2.0·fat······370·b-·defN·80-Feb-01·00:00·filelock/_soft_rw/__init__.py303 -rw----·····2.0·fat······369·b-·defN·80-Feb-01·00:00·filelock/_soft_rw/__init__.py
304 -rw----·····2.0·fat·····9231·b-·defN·80-Feb-01·00:00·filelock/_soft_rw/_async.py304 -rw----·····2.0·fat····14314·b-·defN·80-Feb-01·00:00·filelock/_soft_rw/_async.py
 305 -rw----·····2.0·fat····28940·b-·defN·80-Feb-01·00:00·filelock/_soft_rw/_protocol.py
 306 -rw----·····2.0·fat·····6955·b-·defN·80-Feb-01·00:00·filelock/_soft_rw/_storage.py
305 -rw----·····2.0·fat····42322·b-·defN·80-Feb-01·00:00·filelock/_soft_rw/_sync.py307 -rw----·····2.0·fat····33569·b-·defN·80-Feb-01·00:00·filelock/_soft_rw/_sync.py
306 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·filelock-3.32.0.dist-info/308 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·filelock-4.1.1.dist-info/
307 -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·filelock-3.32.0.dist-info/INSTALLER309 -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·filelock-4.1.1.dist-info/INSTALLER
308 -rw----·····2.0·fat·····2028·b-·defN·80-Feb-01·00:00·filelock-3.32.0.dist-info/METADATA310 -rw----·····2.0·fat·····1976·b-·defN·80-Feb-01·00:00·filelock-4.1.1.dist-info/METADATA
309 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·filelock-3.32.0.dist-info/licenses/311 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·filelock-4.1.1.dist-info/licenses/
310 -rw----·····2.0·fat·····1088·b-·defN·80-Feb-01·00:00·filelock-3.32.0.dist-info/licenses/LICENSE312 -rw----·····2.0·fat·····1088·b-·defN·80-Feb-01·00:00·filelock-4.1.1.dist-info/licenses/LICENSE
311 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·html2text/313 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·html2text/
312 -rw----·····2.0·fat····37885·b-·defN·80-Feb-01·00:00·html2text/__init__.py314 -rw----·····2.0·fat····37885·b-·defN·80-Feb-01·00:00·html2text/__init__.py
313 -rw----·····2.0·fat·······30·b-·defN·80-Feb-01·00:00·html2text/__main__.py315 -rw----·····2.0·fat·······30·b-·defN·80-Feb-01·00:00·html2text/__main__.py
314 -rw----·····2.0·fat·······63·b-·defN·80-Feb-01·00:00·html2text/_typing.py316 -rw----·····2.0·fat·······63·b-·defN·80-Feb-01·00:00·html2text/_typing.py
315 -rw----·····2.0·fat······519·b-·defN·80-Feb-01·00:00·html2text/_version.py317 -rw----·····2.0·fat······519·b-·defN·80-Feb-01·00:00·html2text/_version.py
316 -rw----·····2.0·fat····10300·b-·defN·80-Feb-01·00:00·html2text/cli.py318 -rw----·····2.0·fat····10300·b-·defN·80-Feb-01·00:00·html2text/cli.py
317 -rw----·····2.0·fat·····4052·b-·defN·80-Feb-01·00:00·html2text/config.py319 -rw----·····2.0·fat·····4052·b-·defN·80-Feb-01·00:00·html2text/config.py
Offset 509, 15 lines modifiedOffset 511, 15 lines modified
509 -rw----·····2.0·fat·····3284·b-·defN·80-Feb-01·00:00·reportlab/fonts/hb-test.ttf511 -rw----·····2.0·fat·····3284·b-·defN·80-Feb-01·00:00·reportlab/fonts/hb-test.ttf
510 -rw----·····2.0·fat····34705·b-·defN·80-Feb-01·00:00·reportlab/fonts/sy______.pfb512 -rw----·····2.0·fat····34705·b-·defN·80-Feb-01·00:00·reportlab/fonts/sy______.pfb
511 -rw----·····2.0·fat····49593·b-·defN·80-Feb-01·00:00·reportlab/fonts/zd______.pfb513 -rw----·····2.0·fat····49593·b-·defN·80-Feb-01·00:00·reportlab/fonts/zd______.pfb
512 -rw----·····2.0·fat····75573·b-·defN·80-Feb-01·00:00·reportlab/fonts/zx______.pfb514 -rw----·····2.0·fat····75573·b-·defN·80-Feb-01·00:00·reportlab/fonts/zx______.pfb
513 -rw----·····2.0·fat····96418·b-·defN·80-Feb-01·00:00·reportlab/fonts/zy______.pfb515 -rw----·····2.0·fat····96418·b-·defN·80-Feb-01·00:00·reportlab/fonts/zy______.pfb
514 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·reportlab/graphics/516 -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·reportlab/graphics/
515 -rw----·····2.0·fat······274·b-·defN·80-Feb-01·00:00·reportlab/graphics/__init__.py517 -rw----·····2.0·fat······274·b-·defN·80-Feb-01·00:00·reportlab/graphics/__init__.py
516 -rw----·····2.0·fat····15285·b-·defN·80-Feb-01·00:00·reportlab/graphics/renderPDF.py518 -rw----·····2.0·fat····15309·b-·defN·80-Feb-01·00:00·reportlab/graphics/renderPDF.py
517 -rw----·····2.0·fat····30616·b-·defN·80-Feb-01·00:00·reportlab/graphics/renderPM.py519 -rw----·····2.0·fat····30616·b-·defN·80-Feb-01·00:00·reportlab/graphics/renderPM.py
518 -rw----·····2.0·fat····37937·b-·defN·80-Feb-01·00:00·reportlab/graphics/renderPS.py520 -rw----·····2.0·fat····37937·b-·defN·80-Feb-01·00:00·reportlab/graphics/renderPS.py
519 -rw----·····2.0·fat····38094·b-·defN·80-Feb-01·00:00·reportlab/graphics/renderSVG.py521 -rw----·····2.0·fat····38094·b-·defN·80-Feb-01·00:00·reportlab/graphics/renderSVG.py
520 -rw----·····2.0·fat····13206·b-·defN·80-Feb-01·00:00·reportlab/graphics/renderbase.py522 -rw----·····2.0·fat····13206·b-·defN·80-Feb-01·00:00·reportlab/graphics/renderbase.py
521 -rw----·····2.0·fat····59205·b-·defN·80-Feb-01·00:00·reportlab/graphics/shapes.py523 -rw----·····2.0·fat····59205·b-·defN·80-Feb-01·00:00·reportlab/graphics/shapes.py
Max diff block lines reached; 12297/26430 bytes (46.53%) of diff not shown.
⊟
6.14 KB
zipnote «TEMP»/diffoscope_rc5pjyr8_unsigned/tmpkaztwolb_.zip
    
Offset 477, 33 lines modifiedOffset 477, 33 lines modified
  
477 Filename:·charset_normalizer/cli/__init__.py477 Filename:·charset_normalizer/cli/__init__.py
478 Comment:·478 Comment:·
  
479 Filename:·charset_normalizer/cli/__main__.py479 Filename:·charset_normalizer/cli/__main__.py
480 Comment:·480 Comment:·
  
481 Filename:·charset_normalizer-3.4.9.dist-info/481 Filename:·charset_normalizer-3.5.2.dist-info/
482 Comment:·482 Comment:·
  
483 Filename:·charset_normalizer-3.4.9.dist-info/INSTALLER483 Filename:·charset_normalizer-3.5.2.dist-info/INSTALLER
484 Comment:·484 Comment:·
  
485 Filename:·charset_normalizer-3.4.9.dist-info/METADATA485 Filename:·charset_normalizer-3.5.2.dist-info/METADATA
486 Comment:·486 Comment:·
  
487 Filename:·charset_normalizer-3.4.9.dist-info/entry_points.txt487 Filename:·charset_normalizer-3.5.2.dist-info/entry_points.txt
488 Comment:·488 Comment:·
  
489 Filename:·charset_normalizer-3.4.9.dist-info/top_level.txt489 Filename:·charset_normalizer-3.5.2.dist-info/top_level.txt
490 Comment:·490 Comment:·
  
491 Filename:·charset_normalizer-3.4.9.dist-info/licenses/491 Filename:·charset_normalizer-3.5.2.dist-info/licenses/
492 Comment:·492 Comment:·
  
493 Filename:·charset_normalizer-3.4.9.dist-info/licenses/LICENSE493 Filename:·charset_normalizer-3.5.2.dist-info/licenses/LICENSE
494 Comment:·494 Comment:·
  
495 Filename:·css_parser/495 Filename:·css_parser/
496 Comment:·496 Comment:·
  
497 Filename:·css_parser/__init__.py497 Filename:·css_parser/__init__.py
498 Comment:·498 Comment:·
Offset 699, 27 lines modifiedOffset 699, 27 lines modified
  
699 Filename:·cssselect2/parser.py699 Filename:·cssselect2/parser.py
700 Comment:·700 Comment:·
  
701 Filename:·cssselect2/tree.py701 Filename:·cssselect2/tree.py
702 Comment:·702 Comment:·
  
703 Filename:·cssselect2-0.9.0.dist-info/703 Filename:·cssselect2-0.10.1.dist-info/
704 Comment:·704 Comment:·
  
705 Filename:·cssselect2-0.9.0.dist-info/INSTALLER705 Filename:·cssselect2-0.10.1.dist-info/INSTALLER
706 Comment:·706 Comment:·
  
707 Filename:·cssselect2-0.9.0.dist-info/METADATA707 Filename:·cssselect2-0.10.1.dist-info/METADATA
708 Comment:·708 Comment:·
  
709 Filename:·cssselect2-0.9.0.dist-info/licenses/709 Filename:·cssselect2-0.10.1.dist-info/licenses/
710 Comment:·710 Comment:·
  
711 Filename:·cssselect2-0.9.0.dist-info/licenses/LICENSE711 Filename:·cssselect2-0.10.1.dist-info/licenses/LICENSE
712 Comment:·712 Comment:·
  
713 Filename:·dateutil/713 Filename:·dateutil/
714 Comment:·714 Comment:·
  
715 Filename:·dateutil/__init__.py715 Filename:·dateutil/__init__.py
716 Comment:·716 Comment:·
Offset 903, 30 lines modifiedOffset 903, 36 lines modified
  
903 Filename:·filelock/_soft_rw/__init__.py903 Filename:·filelock/_soft_rw/__init__.py
904 Comment:·904 Comment:·
  
905 Filename:·filelock/_soft_rw/_async.py905 Filename:·filelock/_soft_rw/_async.py
906 Comment:·906 Comment:·
  
 907 Filename:·filelock/_soft_rw/_protocol.py
 908 Comment:·
  
 909 Filename:·filelock/_soft_rw/_storage.py
 910 Comment:·
  
907 Filename:·filelock/_soft_rw/_sync.py911 Filename:·filelock/_soft_rw/_sync.py
908 Comment:·912 Comment:·
  
909 Filename:·filelock-3.32.0.dist-info/913 Filename:·filelock-4.1.1.dist-info/
910 Comment:·914 Comment:·
  
911 Filename:·filelock-3.32.0.dist-info/INSTALLER915 Filename:·filelock-4.1.1.dist-info/INSTALLER
912 Comment:·916 Comment:·
  
913 Filename:·filelock-3.32.0.dist-info/METADATA917 Filename:·filelock-4.1.1.dist-info/METADATA
914 Comment:·918 Comment:·
  
915 Filename:·filelock-3.32.0.dist-info/licenses/919 Filename:·filelock-4.1.1.dist-info/licenses/
916 Comment:·920 Comment:·
  
917 Filename:·filelock-3.32.0.dist-info/licenses/LICENSE921 Filename:·filelock-4.1.1.dist-info/licenses/LICENSE
918 Comment:·922 Comment:·
  
919 Filename:·html2text/923 Filename:·html2text/
920 Comment:·924 Comment:·
  
921 Filename:·html2text/__init__.py925 Filename:·html2text/__init__.py
922 Comment:·926 Comment:·
Offset 2025, 30 lines modifiedOffset 2031, 30 lines modified
  
2025 Filename:·reportlab/platypus/tables.py2031 Filename:·reportlab/platypus/tables.py
2026 Comment:·2032 Comment:·
  
2027 Filename:·reportlab/platypus/xpreformatted.py2033 Filename:·reportlab/platypus/xpreformatted.py
2028 Comment:·2034 Comment:·
  
2029 Filename:·reportlab-5.0.0.dist-info/2035 Filename:·reportlab-5.0.1.dist-info/
2030 Comment:·2036 Comment:·
  
2031 Filename:·reportlab-5.0.0.dist-info/INSTALLER2037 Filename:·reportlab-5.0.1.dist-info/INSTALLER
2032 Comment:·2038 Comment:·
  
2033 Filename:·reportlab-5.0.0.dist-info/METADATA2039 Filename:·reportlab-5.0.1.dist-info/METADATA
2034 Comment:·2040 Comment:·
  
2035 Filename:·reportlab-5.0.0.dist-info/top_level.txt2041 Filename:·reportlab-5.0.1.dist-info/top_level.txt
2036 Comment:·2042 Comment:·
  
2037 Filename:·reportlab-5.0.0.dist-info/licenses/2043 Filename:·reportlab-5.0.1.dist-info/licenses/
2038 Comment:·2044 Comment:·
  
2039 Filename:·reportlab-5.0.0.dist-info/licenses/LICENSE2045 Filename:·reportlab-5.0.1.dist-info/licenses/LICENSE
2040 Comment:·2046 Comment:·
  
2041 Filename:·six-1.17.0.dist-info/2047 Filename:·six-1.17.0.dist-info/
2042 Comment:·2048 Comment:·
  
Max diff block lines reached; 2561/6172 bytes (41.49%) of diff not shown.
⊟
2.76 MB
zipdetails --redact --walk --utc {}
    
Offset 3532, 35923 lines modifiedOffset 3532, 35872 lines modified
3532 07746D·Extract·Zip·Spec······14·(20)·'2.0'3532 07746D·Extract·Zip·Spec······14·(20)·'2.0'
3533 07746E·Extract·OS············00·(0)·'MS-DOS'3533 07746E·Extract·OS············00·(0)·'MS-DOS'
3534 07746F·General·Purpose·Flag··0800·(2048)3534 07746F·General·Purpose·Flag··0800·(2048)
3535 ·······[Bits·1-2]············0·'Normal·Compression'3535 ·······[Bits·1-2]············0·'Normal·Compression'
3536 ·······[Bit·11]··············1·'Language·Encoding'3536 ·······[Bit·11]··············1·'Language·Encoding'
3537 077471·Compression·Method····0008·(8)·'Deflated'3537 077471·Compression·Method····0008·(8)·'Deflated'
3538 077473·Modification·Time·····00410000·(4259840)·'Fri·Feb··1·00:00:00·1980'3538 077473·Modification·Time·····00410000·(4259840)·'Fri·Feb··1·00:00:00·1980'
3539 077477·CRC···················84EED9B3·(2230245811)3539 077477·CRC···················36D9FA28·(920255016)
3540 07747B·Compressed·Size·······00000324·(804)3540 07747B·Compressed·Size·······0000031C·(796)
3541 07747F·Uncompressed·Size·····00000636·(1590)3541 07747F·Uncompressed·Size·····0000062E·(1582)
3542 077483·Filename·Length·······001E·(30)3542 077483·Filename·Length·······001E·(30)
3543 077485·Extra·Length··········0014·(20)3543 077485·Extra·Length··········0014·(20)
3544 077487·Filename··············'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'3544 077487·Filename··············'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
3545 #3545 #
3546 #·WARNING:·Offset·0x77487:·Filename·'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'3546 #·WARNING:·Offset·0x77487:·Filename·'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
3547 #··········Zero·length·filename3547 #··········Zero·length·filename
3548 #3548 #
3549 0774A5·Extra·ID·#1···········0001·(1)·'ZIP64'3549 0774A5·Extra·ID·#1···········0001·(1)·'ZIP64'
3550 0774A7···Length··············0010·(16)3550 0774A7···Length··············0010·(16)
3551 0774A9···Uncompressed·Size···0000000000000636·(1590)3551 0774A9···Uncompressed·Size···000000000000062E·(1582)
3552 0774B1···Compressed·Size·····0000000000000324·(804)3552 0774B1···Compressed·Size·····000000000000031C·(796)
3553 0774B9·PAYLOAD3553 0774B9·PAYLOAD
Diff chunk too large, falling back to line-by-line diff (2567 lines added, 2567 lines removed)
  
3554 0777DD·LOCAL·HEADER·#149·····04034B50·(67324752)3554 0777D5·LOCAL·HEADER·#149·····04034B50·(67324752)
3555 0777E1·Extract·Zip·Spec······14·(20)·'2.0'3555 0777D9·Extract·Zip·Spec······14·(20)·'2.0'
3556 0777E2·Extract·OS············00·(0)·'MS-DOS'3556 0777DA·Extract·OS············00·(0)·'MS-DOS'
3557 0777E3·General·Purpose·Flag··0800·(2048)3557 0777DB·General·Purpose·Flag··0800·(2048)
3558 ·······[Bits·1-2]············0·'Normal·Compression'3558 ·······[Bits·1-2]············0·'Normal·Compression'
3559 ·······[Bit·11]··············1·'Language·Encoding'3559 ·······[Bit·11]··············1·'Language·Encoding'
3560 0777E5·Compression·Method····0008·(8)·'Deflated'3560 0777DD·Compression·Method····0008·(8)·'Deflated'
3561 0777E7·Modification·Time·····00410000·(4259840)·'Fri·Feb··1·00:00:00·1980'3561 0777DF·Modification·Time·····00410000·(4259840)·'Fri·Feb··1·00:00:00·1980'
3562 0777EB·CRC···················35633DF4·(895696372)3562 0777E3·CRC···················35633DF4·(895696372)
3563 0777EF·Compressed·Size·······00000055·(85)3563 0777E7·Compressed·Size·······00000055·(85)
3564 0777F3·Uncompressed·Size·····0000006D·(109)3564 0777EB·Uncompressed·Size·····0000006D·(109)
3565 0777F7·Filename·Length·······001E·(30)3565 0777EF·Filename·Length·······001E·(30)
3566 0777F9·Extra·Length··········0014·(20)3566 0777F1·Extra·Length··········0014·(20)
3567 0777FB·Filename··············'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'3567 0777F3·Filename··············'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
3568 #3568 #
3569 #·WARNING:·Offset·0x777FB:·Filename·'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'3569 #·WARNING:·Offset·0x777F3:·Filename·'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
3570 #··········Zero·length·filename3570 #··········Zero·length·filename
3571 #3571 #
3572 077819·Extra·ID·#1···········0001·(1)·'ZIP64'3572 077811·Extra·ID·#1···········0001·(1)·'ZIP64'
3573 07781B···Length··············0010·(16)3573 077813···Length··············0010·(16)
3574 07781D···Uncompressed·Size···000000000000006D·(109)3574 077815···Uncompressed·Size···000000000000006D·(109)
3575 077825···Compressed·Size·····0000000000000055·(85)3575 07781D···Compressed·Size·····0000000000000055·(85)
3576 07782D·PAYLOAD···············XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX3576 077825·PAYLOAD···············XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  
3577 077882·LOCAL·HEADER·#150·····04034B50·(67324752)3577 07787A·LOCAL·HEADER·#150·····04034B50·(67324752)
3578 077886·Extract·Zip·Spec······14·(20)·'2.0'3578 07787E·Extract·Zip·Spec······14·(20)·'2.0'
3579 077887·Extract·OS············00·(0)·'MS-DOS'3579 07787F·Extract·OS············00·(0)·'MS-DOS'
3580 077888·General·Purpose·Flag··0800·(2048)3580 077880·General·Purpose·Flag··0800·(2048)
3581 ·······[Bits·1-2]············0·'Normal·Compression'3581 ·······[Bits·1-2]············0·'Normal·Compression'
3582 ·······[Bit·11]··············1·'Language·Encoding'3582 ·······[Bit·11]··············1·'Language·Encoding'
3583 07788A·Compression·Method····0008·(8)·'Deflated'3583 077882·Compression·Method····0008·(8)·'Deflated'
3584 07788C·Modification·Time·····00410000·(4259840)·'Fri·Feb··1·00:00:00·1980'3584 077884·Modification·Time·····00410000·(4259840)·'Fri·Feb··1·00:00:00·1980'
3585 077890·CRC···················FABFCC0E·(4206873614)3585 077888·CRC···················155BD86E·(358340718)
3586 077894·Compressed·Size·······00002504·(9476)3586 07788C·Compressed·Size·······000020BB·(8379)
3587 077898·Uncompressed·Size·····0000A555·(42325)3587 077890·Uncompressed·Size·····00008BBE·(35774)
3588 07789C·Filename·Length·······0019·(25)3588 077894·Filename·Length·······0019·(25)
3589 07789E·Extra·Length··········0014·(20)3589 077896·Extra·Length··········0014·(20)
3590 0778A0·Filename··············'XXXXXXXXXXXXXXXXXXXXXXXXX'3590 077898·Filename··············'XXXXXXXXXXXXXXXXXXXXXXXXX'
3591 #3591 #
3592 #·WARNING:·Offset·0x778A0:·Filename·'XXXXXXXXXXXXXXXXXXXXXXXXX'3592 #·WARNING:·Offset·0x77898:·Filename·'XXXXXXXXXXXXXXXXXXXXXXXXX'
3593 #··········Zero·length·filename3593 #··········Zero·length·filename
3594 #3594 #
3595 0778B9·Extra·ID·#1···········0001·(1)·'ZIP64'3595 0778B1·Extra·ID·#1···········0001·(1)·'ZIP64'
3596 0778BB···Length··············0010·(16)3596 0778B3···Length··············0010·(16)
3597 0778BD···Uncompressed·Size···000000000000A555·(42325)3597 0778B5···Uncompressed·Size···0000000000008BBE·(35774)
3598 0778C5···Compressed·Size·····0000000000002504·(9476)3598 0778BD···Compressed·Size·····00000000000020BB·(8379)
3599 0778CD·PAYLOAD3599 0778C5·PAYLOAD
  
3600 079DD1·LOCAL·HEADER·#151·····04034B50·(67324752)3600 079980·LOCAL·HEADER·#151·····04034B50·(67324752)
3601 079DD5·Extract·Zip·Spec······14·(20)·'2.0'3601 079984·Extract·Zip·Spec······14·(20)·'2.0'
3602 079DD6·Extract·OS············00·(0)·'MS-DOS'3602 079985·Extract·OS············00·(0)·'MS-DOS'
3603 079DD7·General·Purpose·Flag··0800·(2048)3603 079986·General·Purpose·Flag··0800·(2048)
3604 ·······[Bits·1-2]············0·'Normal·Compression'3604 ·······[Bits·1-2]············0·'Normal·Compression'
3605 ·······[Bit·11]··············1·'Language·Encoding'3605 ·······[Bit·11]··············1·'Language·Encoding'
3606 079DD9·Compression·Method····0008·(8)·'Deflated'3606 079988·Compression·Method····0008·(8)·'Deflated'
3607 079DDB·Modification·Time·····00410000·(4259840)·'Fri·Feb··1·00:00:00·1980'3607 07998A·Modification·Time·····00410000·(4259840)·'Fri·Feb··1·00:00:00·1980'
3608 079DDF·CRC···················16049338·(369398584)3608 07998E·CRC···················16049338·(369398584)
3609 079DE3·Compressed·Size·······000010D3·(4307)3609 079992·Compressed·Size·······000010D3·(4307)
3610 079DE7·Uncompressed·Size·····00003E6C·(15980)3610 079996·Uncompressed·Size·····00003E6C·(15980)
3611 079DEB·Filename·Length·······0018·(24)3611 07999A·Filename·Length·······0018·(24)
3612 079DED·Extra·Length··········0014·(20)3612 07999C·Extra·Length··········0014·(20)
3613 079DEF·Filename··············'XXXXXXXXXXXXXXXXXXXXXXXX'3613 07999E·Filename··············'XXXXXXXXXXXXXXXXXXXXXXXX'
3614 #3614 #
3615 #·WARNING:·Offset·0x79DEF:·Filename·'XXXXXXXXXXXXXXXXXXXXXXXX'3615 #·WARNING:·Offset·0x7999E:·Filename·'XXXXXXXXXXXXXXXXXXXXXXXX'
3616 #··········Zero·length·filename3616 #··········Zero·length·filename
3617 #3617 #
3618 079E07·Extra·ID·#1···········0001·(1)·'ZIP64'3618 0799B6·Extra·ID·#1···········0001·(1)·'ZIP64'
3619 079E09···Length··············0010·(16)3619 0799B8···Length··············0010·(16)
3620 079E0B···Uncompressed·Size···0000000000003E6C·(15980)3620 0799BA···Uncompressed·Size···0000000000003E6C·(15980)
3621 079E13···Compressed·Size·····00000000000010D3·(4307)3621 0799C2···Compressed·Size·····00000000000010D3·(4307)
3622 079E1B·PAYLOAD3622 0799CA·PAYLOAD
  
3623 07AEEE·LOCAL·HEADER·#152·····04034B50·(67324752)3623 07AA9D·LOCAL·HEADER·#152·····04034B50·(67324752)
3624 07AEF2·Extract·Zip·Spec······14·(20)·'2.0'3624 07AAA1·Extract·Zip·Spec······14·(20)·'2.0'
3625 07AEF3·Extract·OS············00·(0)·'MS-DOS'3625 07AAA2·Extract·OS············00·(0)·'MS-DOS'
3626 07AEF4·General·Purpose·Flag··0800·(2048)3626 07AAA3·General·Purpose·Flag··0800·(2048)
3627 ·······[Bits·1-2]············0·'Normal·Compression'3627 ·······[Bits·1-2]············0·'Normal·Compression'
3628 ·······[Bit·11]··············1·'Language·Encoding'3628 ·······[Bit·11]··············1·'Language·Encoding'
3629 07AEF6·Compression·Method····0008·(8)·'Deflated'3629 07AAA5·Compression·Method····0008·(8)·'Deflated'
3630 07AEF8·Modification·Time·····00410000·(4259840)·'Fri·Feb··1·00:00:00·1980'3630 07AAA7·Modification·Time·····00410000·(4259840)·'Fri·Feb··1·00:00:00·1980'
3631 07AEFC·CRC···················57A86875·(1470654581)3631 07AAAB·CRC···················FA97DBAA·(4204256170)
3632 07AF00·Compressed·Size·······00003253·(12883)3632 07AAAF·Compressed·Size·······00003DB4·(15796)
3633 07AF04·Uncompressed·Size·····0000AE50·(44624)3633 07AAB3·Uncompressed·Size·····0000ED8C·(60812)
3634 07AF08·Filename·Length·······001E·(30)3634 07AAB7·Filename·Length·······001E·(30)
3635 07AF0A·Extra·Length··········0014·(20)3635 07AAB9·Extra·Length··········0014·(20)
3636 07AF0C·Filename··············'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'3636 07AABB·Filename··············'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
3637 #3637 #
3638 #·WARNING:·Offset·0x7AF0C:·Filename·'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'3638 #·WARNING:·Offset·0x7AABB:·Filename·'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
3639 #··········Zero·length·filename3639 #··········Zero·length·filename
3640 #3640 #
3641 07AF2A·Extra·ID·#1···········0001·(1)·'ZIP64'3641 07AAD9·Extra·ID·#1···········0001·(1)·'ZIP64'
3642 07AF2C···Length··············0010·(16)3642 07AADB···Length··············0010·(16)
3643 07AF2E···Uncompressed·Size···000000000000AE50·(44624)3643 07AADD···Uncompressed·Size···000000000000ED8C·(60812)
3644 07AF36···Compressed·Size·····0000000000003253·(12883)3644 07AAE5···Compressed·Size·····0000000000003DB4·(15796)
3645 07AF3E·PAYLOAD3645 07AAED·PAYLOAD
  
3646 07E191·LOCAL·HEADER·#153·····04034B50·(67324752)3646 07E8A1·LOCAL·HEADER·#153·····04034B50·(67324752)
3647 07E195·Extract·Zip·Spec······14·(20)·'2.0'3647 07E8A5·Extract·Zip·Spec······14·(20)·'2.0'
3648 07E196·Extract·OS············00·(0)·'MS-DOS'3648 07E8A6·Extract·OS············00·(0)·'MS-DOS'
3649 07E197·General·Purpose·Flag··0800·(2048)3649 07E8A7·General·Purpose·Flag··0800·(2048)
3650 ·······[Bits·1-2]············0·'Normal·Compression'3650 ·······[Bits·1-2]············0·'Normal·Compression'
3651 ·······[Bit·11]··············1·'Language·Encoding'3651 ·······[Bit·11]··············1·'Language·Encoding'
3652 07E199·Compression·Method····0008·(8)·'Deflated'3652 07E8A9·Compression·Method····0008·(8)·'Deflated'
Max diff block lines reached; 2670662/2891635 bytes (92.36%) of diff not shown.
⊟
599 B
charset_normalizer/__init__.py
    
Offset 11, 15 lines modifiedOffset 11, 15 lines modified
11 ···>>>·results·=·from_bytes('Bсеки·човек·има·право·на·образование.·Oбразованието!'.encode('utf_8'))11 ···>>>·results·=·from_bytes('Bсеки·човек·има·право·на·образование.·Oбразованието!'.encode('utf_8'))
12 ···>>>·best_guess·=·results.best()12 ···>>>·best_guess·=·results.best()
13 ···>>>·str(best_guess)13 ···>>>·str(best_guess)
14 ···'Bсеки·човек·има·право·на·образование.·Oбразованието!'14 ···'Bсеки·човек·има·право·на·образование.·Oбразованието!'
  
15 Others·methods·and·usages·are·available·-·see·the·full·documentation15 Others·methods·and·usages·are·available·-·see·the·full·documentation
16 at·<https://github.com/Ousret/charset_normalizer>.16 at·<https://github.com/Ousret/charset_normalizer>.
17 :copyright:·(c)·2021·by·Ahmed·TAHRI17 :copyright:·(c)·Ahmed·TAHRI
18 :license:·MIT,·see·LICENSE·for·more·details.18 :license:·MIT,·see·LICENSE·for·more·details.
19 """19 """
  
20 from·__future__·import·annotations20 from·__future__·import·annotations
  
21 import·logging21 import·logging
  
⊟
14.6 KB
charset_normalizer/api.py
    
Offset 136, 24 lines modifiedOffset 136, 22 lines modified
  
136 ····is_too_small_sequence:·bool·=·len(sequences)·<·TOO_SMALL_SEQUENCE136 ····is_too_small_sequence:·bool·=·len(sequences)·<·TOO_SMALL_SEQUENCE
137 ····is_too_large_sequence:·bool·=·len(sequences)·>=·TOO_BIG_SEQUENCE137 ····is_too_large_sequence:·bool·=·len(sequences)·>=·TOO_BIG_SEQUENCE
  
138 ····if·is_too_small_sequence:138 ····if·is_too_small_sequence:
139 ········logger.log(139 ········logger.log(
140 ············TRACE,140 ············TRACE,
141 ············"Trying·to·detect·encoding·from·a·tiny·portion·of·({})·byte(s).".format(141 ············"Trying·to·detect·encoding·from·a·tiny·portion·of·(%i)·byte(s).",
142 ················length142 ············length,
143 ············), 
144 ········)143 ········)
145 ····elif·is_too_large_sequence:144 ····elif·is_too_large_sequence:
146 ········logger.log(145 ········logger.log(
147 ············TRACE,146 ············TRACE,
148 ············"Using·lazy·str·decoding·because·the·payload·is·quite·large,·({})·byte(s).".format(147 ············"Using·lazy·str·decoding·because·the·payload·is·quite·large,·(%i)·byte(s).",
149 ················length148 ············length,
150 ············), 
151 ········)149 ········)
  
152 ····prioritized_encodings:·list[str]·=·[]150 ····prioritized_encodings:·list[str]·=·[]
  
153 ····specified_encoding:·str·|·None·=·(151 ····specified_encoding:·str·|·None·=·(
154 ········any_specified_encoding(sequences)·if·preemptive_behaviour·else·None152 ········any_specified_encoding(sequences)·if·preemptive_behaviour·else·None
155 ····)153 ····)
Offset 166, 20 lines modifiedOffset 164, 14 lines modified
166 ············specified_encoding,164 ············specified_encoding,
167 ········)165 ········)
  
168 ····tested:·set[str]·=·set()166 ····tested:·set[str]·=·set()
169 ····tested_but_hard_failure:·list[str]·=·[]167 ····tested_but_hard_failure:·list[str]·=·[]
170 ····tested_but_soft_failure:·list[str]·=·[]168 ····tested_but_soft_failure:·list[str]·=·[]
171 ····soft_failure_skip:·set[str]·=·set()169 ····soft_failure_skip:·set[str]·=·set()
172 ····success_fast_tracked:·set[str]·=·set() 
  
173 ····#·Cache·for·decoded·payload·deduplication:·hash(decoded_payload)·->·(mean_mess_ratio,·cd_ratios_merged,·passed) 
174 ····#·When·multiple·encodings·decode·to·the·exact·same·string,·we·can·skip·the·expensive 
175 ····#·mess_ratio·and·coherence_ratio·analysis·and·reuse·the·results·from·the·first·encoding. 
176 ····payload_result_cache:·dict[int,·tuple[float,·list[tuple[str,·float]],·bool]]·=·{} 
  
177 ····#·Avoid·unoptimized·RSS·usage.170 ····#·Avoid·unoptimized·RSS·usage.
178 ····#·this·cache·is·mostly·interesting·for171 ····#·this·cache·is·mostly·interesting·for
179 ····#·local·usage.·Garbage·collected·at·the172 ····#·local·usage.·Garbage·collected·at·the
180 ····#·end.·Like·it·should.173 ····#·end.·Like·it·should.
181 ····cached_mess_ratio·=·lru_cache(maxsize=None)(mess_ratio)174 ····cached_mess_ratio·=·lru_cache(maxsize=None)(mess_ratio)
182 ····cached_coherence_ratio·=·lru_cache(maxsize=None)(coherence_ratio)175 ····cached_coherence_ratio·=·lru_cache(maxsize=None)(coherence_ratio)
Offset 218, 15 lines modifiedOffset 210, 15 lines modified
218 ····results:·CharsetMatches·=·CharsetMatches()210 ····results:·CharsetMatches·=·CharsetMatches()
  
219 ····early_stop_results:·CharsetMatches·=·CharsetMatches()211 ····early_stop_results:·CharsetMatches·=·CharsetMatches()
  
220 ····sig_encoding,·sig_payload·=·identify_sig_or_bom(sequences)212 ····sig_encoding,·sig_payload·=·identify_sig_or_bom(sequences)
  
221 ····if·sig_encoding·is·not·None:213 ····if·sig_encoding·is·not·None:
222 ········prioritized_encodings.append(sig_encoding)214 ········prioritized_encodings.insert(0,·sig_encoding)
223 ········logger.log(215 ········logger.log(
224 ············TRACE,216 ············TRACE,
225 ············"Detected·a·SIG·or·BOM·mark·on·first·%i·byte(s).·Priority·+1·given·for·%s.",217 ············"Detected·a·SIG·or·BOM·mark·on·first·%i·byte(s).·Priority·+1·given·for·%s.",
226 ············len(sig_payload),218 ············len(sig_payload),
227 ············sig_encoding,219 ············sig_encoding,
228 ········)220 ········)
  
Offset 274, 23 lines modifiedOffset 266, 14 lines modified
274 ············logger.log(266 ············logger.log(
275 ················TRACE,267 ················TRACE,
276 ················"%s·is·deemed·too·similar·to·a·code·page·that·was·already·considered·unsuited.·Continuing!",268 ················"%s·is·deemed·too·similar·to·a·code·page·that·was·already·considered·unsuited.·Continuing!",
277 ················encoding_iana,269 ················encoding_iana,
278 ············)270 ············)
279 ············continue271 ············continue
  
280 ········#·Skip·encodings·that·were·already·fast-tracked·from·a·similar·successful·encoding. 
281 ········if·encoding_iana·in·success_fast_tracked: 
282 ············logger.log( 
283 ················TRACE, 
284 ················"Skipping·%s:·already·fast-tracked·from·a·similar·successful·encoding.", 
285 ················encoding_iana, 
286 ············) 
287 ············continue 
  
288 ········try:272 ········try:
289 ············is_multi_byte_decoder:·bool·=·is_multi_byte_encoding(encoding_iana)273 ············is_multi_byte_decoder:·bool·=·is_multi_byte_encoding(encoding_iana)
290 ········except·(ModuleNotFoundError,·ImportError):··#·Defensive:274 ········except·(ModuleNotFoundError,·ImportError):··#·Defensive:
291 ············logger.log(275 ············logger.log(
292 ················TRACE,276 ················TRACE,
293 ················"Encoding·%s·does·not·provide·an·IncrementalDecoder",277 ················"Encoding·%s·does·not·provide·an·IncrementalDecoder",
294 ················encoding_iana,278 ················encoding_iana,
Offset 480, 44 lines modifiedOffset 463, 41 lines modified
480 ················"LazyStr·Loading:·After·MD·chunk·decode,·code·page·%s·does·not·fit·given·bytes·sequence·at·ALL.·%s",463 ················"LazyStr·Loading:·After·MD·chunk·decode,·code·page·%s·does·not·fit·given·bytes·sequence·at·ALL.·%s",
481 ················encoding_iana,464 ················encoding_iana,
482 ················str(e),465 ················str(e),
483 ············)466 ············)
484 ············early_stop_count·=·max_chunk_gave_up467 ············early_stop_count·=·max_chunk_gave_up
485 ············lazy_str_hard_failure·=·True468 ············lazy_str_hard_failure·=·True
  
 469 ········mean_mess_ratio:·float·=·sum(md_ratios)·/·len(md_ratios)·if·md_ratios·else·0.0
  
486 ········#·We·might·want·to·check·the·sequence·again·with·the·whole·content470 ········#·We·might·want·to·check·the·sequence·again·with·the·whole·content,
487 ········#·Only·if·initial·MD·tests·passes471 ········#·but·only·if·initial·MD·tests·passed.
488 ········if·(472 ········if·(
489 ············not·lazy_str_hard_failure473 ············not·lazy_str_hard_failure
490 ············and·is_too_large_sequence474 ············and·is_too_large_sequence
491 ············and·not·is_multi_byte_decoder475 ············and·not·is_multi_byte_decoder
 476 ············and·mean_mess_ratio·<·threshold
 477 ············and·early_stop_count·<·max_chunk_gave_up
492 ········):478 ········):
493 ············try:479 ············try:
494 ················sequences[int(50e3)·:].decode(encoding_iana,·errors="strict")480 ················sequences[int(50e3)·:].decode(encoding_iana,·errors="strict")
495 ············except·UnicodeDecodeError·as·e:481 ············except·UnicodeDecodeError·as·e:
496 ················logger.log(482 ················logger.log(
497 ····················TRACE,483 ····················TRACE,
498 ····················"LazyStr·Loading:·After·final·lookup,·code·page·%s·does·not·fit·given·bytes·sequence·at·ALL.·%s",484 ····················"LazyStr·Loading:·After·final·lookup,·code·page·%s·does·not·fit·given·bytes·sequence·at·ALL.·%s",
499 ····················encoding_iana,485 ····················encoding_iana,
500 ····················str(e),486 ····················str(e),
501 ················)487 ················)
502 ················tested_but_hard_failure.append(encoding_iana)488 ················tested_but_hard_failure.append(encoding_iana)
503 ················continue489 ················continue
  
504 ········mean_mess_ratio:·float·=·sum(md_ratios)·/·len(md_ratios)·if·md_ratios·else·0.0 
505 ········if·mean_mess_ratio·>=·threshold·or·early_stop_count·>=·max_chunk_gave_up:490 ········if·mean_mess_ratio·>=·threshold·or·early_stop_count·>=·max_chunk_gave_up:
506 ············tested_but_soft_failure.append(encoding_iana)491 ············tested_but_soft_failure.append(encoding_iana)
507 ············if·encoding_iana·in·IANA_SUPPORTED_SIMILAR:492 ············if·encoding_iana·in·IANA_SUPPORTED_SIMILAR:
508 ················soft_failure_skip.update(IANA_SUPPORTED_SIMILAR[encoding_iana])493 ················soft_failure_skip.update(IANA_SUPPORTED_SIMILAR[encoding_iana])
509 ············#·Cache·this·soft-failure·so·identical·decoding·from·other·encodings 
510 ············#·can·be·skipped·immediately. 
511 ············if·decoded_payload·is·not·None·and·not·is_multi_byte_decoder: 
512 ················payload_result_cache.setdefault( 
513 ····················hash(decoded_payload),·(mean_mess_ratio,·[],·False) 
514 ················) 
Max diff block lines reached; 9361/14866 bytes (62.97%) of diff not shown.
⊟
17.3 KB
charset_normalizer/constant.py
    
Offset 371, 14 lines modifiedOffset 371, 420 lines modified
371 ····"CJK·Unified·Ideographs·Extension·J":·range(205744,·210048),371 ····"CJK·Unified·Ideographs·Extension·J":·range(205744,·210048),
372 ····"Tags":·range(917504,·917632),372 ····"Tags":·range(917504,·917632),
373 ····"Variation·Selectors·Supplement":·range(917760,·918000),373 ····"Variation·Selectors·Supplement":·range(917760,·918000),
374 ····"Supplementary·Private·Use·Area-A":·range(983040,·1048576),374 ····"Supplementary·Private·Use·Area-A":·range(983040,·1048576),
375 ····"Supplementary·Private·Use·Area-B":·range(1048576,·1114112),375 ····"Supplementary·Private·Use·Area-B":·range(1048576,·1114112),
376 }376 }
  
 377 #·Canonical·family·for·every·Unicode·range·above.·Keep·this·exhaustive·and
 378 #·explicit:·official·block·names·are·labels,·not·a·grammar·we·should·parse.
 379 _RANGE_FAMILIES:·dict[str,·str]·=·{
 380 ····"Control·character":·"Control·character",
 381 ····"Basic·Latin":·"Latin",
 382 ····"Latin-1·Supplement":·"Latin",
 383 ····"Latin·Extended-A":·"Latin",
 384 ····"Latin·Extended-B":·"Latin",
 385 ····"IPA·Extensions":·"IPA",
 386 ····"Spacing·Modifier·Letters":·"Spacing·Modifier·Letters",
 387 ····"Combining·Diacritical·Marks":·"Combining",
 388 ····"Greek·and·Coptic":·"Greek",
 389 ····"Cyrillic":·"Cyrillic",
 390 ····"Cyrillic·Supplement":·"Cyrillic",
 391 ····"Armenian":·"Armenian",
 392 ····"Hebrew":·"Hebrew",
 393 ····"Arabic":·"Arabic",
 394 ····"Syriac":·"Syriac",
 395 ····"Arabic·Supplement":·"Arabic",
 396 ····"Thaana":·"Thaana",
 397 ····"NKo":·"NKo",
 398 ····"Samaritan":·"Samaritan",
 399 ····"Mandaic":·"Mandaic",
 400 ····"Syriac·Supplement":·"Syriac",
 401 ····"Arabic·Extended-B":·"Arabic",
 402 ····"Arabic·Extended-A":·"Arabic",
 403 ····"Devanagari":·"Devanagari",
 404 ····"Bengali":·"Bengali",
 405 ····"Gurmukhi":·"Gurmukhi",
 406 ····"Gujarati":·"Gujarati",
 407 ····"Oriya":·"Oriya",
 408 ····"Tamil":·"Tamil",
 409 ····"Telugu":·"Telugu",
 410 ····"Kannada":·"Kannada",
 411 ····"Malayalam":·"Malayalam",
 412 ····"Sinhala":·"Sinhala",
 413 ····"Thai":·"Thai",
 414 ····"Lao":·"Lao",
 415 ····"Tibetan":·"Tibetan",
 416 ····"Myanmar":·"Myanmar",
 417 ····"Georgian":·"Georgian",
 418 ····"Hangul·Jamo":·"Hangul",
 419 ····"Ethiopic":·"Ethiopic",
 420 ····"Ethiopic·Supplement":·"Ethiopic",
 421 ····"Cherokee":·"Cherokee",
 422 ····"Unified·Canadian·Aboriginal·Syllabics":·"Unified·Canadian·Aboriginal·Syllabics",
 423 ····"Ogham":·"Ogham",
 424 ····"Runic":·"Runic",
 425 ····"Tagalog":·"Tagalog",
 426 ····"Hanunoo":·"Hanunoo",
 427 ····"Buhid":·"Buhid",
 428 ····"Tagbanwa":·"Tagbanwa",
 429 ····"Khmer":·"Khmer",
 430 ····"Mongolian":·"Mongolian",
 431 ····"Unified·Canadian·Aboriginal·Syllabics·Extended":·"Unified·Canadian·Aboriginal·Syllabics",
 432 ····"Limbu":·"Limbu",
 433 ····"Tai·Le":·"Tai·Le",
 434 ····"New·Tai·Lue":·"New·Tai·Lue",
 435 ····"Khmer·Symbols":·"Khmer",
 436 ····"Buginese":·"Buginese",
 437 ····"Tai·Tham":·"Tai·Tham",
 438 ····"Combining·Diacritical·Marks·Extended":·"Combining",
 439 ····"Balinese":·"Balinese",
 440 ····"Sundanese":·"Sundanese",
 441 ····"Batak":·"Batak",
 442 ····"Lepcha":·"Lepcha",
 443 ····"Ol·Chiki":·"Ol·Chiki",
 444 ····"Cyrillic·Extended-C":·"Cyrillic",
 445 ····"Georgian·Extended":·"Georgian",
 446 ····"Sundanese·Supplement":·"Sundanese",
 447 ····"Vedic·Extensions":·"Vedic",
 448 ····"Phonetic·Extensions":·"Phonetic",
 449 ····"Phonetic·Extensions·Supplement":·"Phonetic",
 450 ····"Combining·Diacritical·Marks·Supplement":·"Combining",
 451 ····"Latin·Extended·Additional":·"Latin",
 452 ····"Greek·Extended":·"Greek",
 453 ····"General·Punctuation":·"Punctuation",
 454 ····"Superscripts·and·Subscripts":·"Superscripts·and·Subscripts",
 455 ····"Currency·Symbols":·"Currency·Symbols",
 456 ····"Combining·Diacritical·Marks·for·Symbols":·"Combining",
 457 ····"Letterlike·Symbols":·"Letterlike·Symbols",
 458 ····"Number·Forms":·"Number·Forms",
 459 ····"Arrows":·"Arrows",
 460 ····"Mathematical·Operators":·"Mathematical",
 461 ····"Miscellaneous·Technical":·"Miscellaneous·Technical",
 462 ····"Control·Pictures":·"Control·Pictures",
 463 ····"Optical·Character·Recognition":·"Optical·Character·Recognition",
 464 ····"Enclosed·Alphanumerics":·"Enclosed·Alphanumerics",
 465 ····"Box·Drawing":·"Box·Drawing",
 466 ····"Block·Elements":·"Block·Elements",
 467 ····"Geometric·Shapes":·"Geometric·Shapes",
 468 ····"Miscellaneous·Symbols":·"Miscellaneous·Symbols",
 469 ····"Dingbats":·"Dingbats",
 470 ····"Miscellaneous·Mathematical·Symbols-A":·"Mathematical",
 471 ····"Supplemental·Arrows-A":·"Arrows",
 472 ····"Braille·Patterns":·"Braille",
 473 ····"Supplemental·Arrows-B":·"Arrows",
 474 ····"Miscellaneous·Mathematical·Symbols-B":·"Mathematical",
 475 ····"Supplemental·Mathematical·Operators":·"Mathematical",
 476 ····"Miscellaneous·Symbols·and·Arrows":·"Miscellaneous·Symbols·and·Arrows",
 477 ····"Glagolitic":·"Glagolitic",
 478 ····"Latin·Extended-C":·"Latin",
 479 ····"Coptic":·"Coptic",
 480 ····"Georgian·Supplement":·"Georgian",
 481 ····"Tifinagh":·"Tifinagh",
 482 ····"Ethiopic·Extended":·"Ethiopic",
 483 ····"Cyrillic·Extended-A":·"Cyrillic",
 484 ····"Supplemental·Punctuation":·"Punctuation",
 485 ····"CJK·Radicals·Supplement":·"CJK",
 486 ····"Kangxi·Radicals":·"CJK",
 487 ····"Ideographic·Description·Characters":·"CJK",
 488 ····"CJK·Symbols·and·Punctuation":·"CJK",
 489 ····"Hiragana":·"Hiragana",
 490 ····"Katakana":·"Katakana",
 491 ····"Bopomofo":·"Bopomofo",
 492 ····"Hangul·Compatibility·Jamo":·"Hangul",
 493 ····"Kanbun":·"Kanbun",
 494 ····"Bopomofo·Extended":·"Bopomofo",
 495 ····"CJK·Strokes":·"CJK",
 496 ····"Katakana·Phonetic·Extensions":·"Katakana",
Max diff block lines reached; 1565/17703 bytes (8.84%) of diff not shown.
⊟
30.8 KB
charset_normalizer/md.py
    
Offset 1, 37 lines modifiedOffset 1, 34 lines modified
1 from·__future__·import·annotations1 from·__future__·import·annotations
  
2 import·sys 
3 from·functools·import·lru_cache2 from·functools·import·lru_cache
4 from·logging·import·getLogger3 from·logging·import·getLogger
  
5 if·sys.version_info·>=·(3,·8): 
6 ····from·typing·import·final 
7 else: 
8 ····try: 
9 ········from·typing_extensions·import·final 
10 ····except·ImportError: 
  
11 ········def·final(cls):··#·type:·ignore[misc,no-untyped-def] 
12 ············return·cls 
  
  
13 from·.constant·import·(4 from·.constant·import·(
14 ····COMMON_CJK_CHARACTERS,5 ····COMMON_CJK_CHARACTERS,
15 ····COMMON_SAFE_ASCII_CHARACTERS,6 ····COMMON_SAFE_ASCII_CHARACTERS,
16 ····TRACE,7 ····TRACE,
17 ····UNICODE_SECONDARY_RANGE_KEYWORD,8 ····CompatibleFamillyRange,
18 ····_ACCENTUATED,9 ····_ACCENTUATED,
19 ····_ARABIC,10 ····_ARABIC,
20 ····_ARABIC_ISOLATED_FORM,11 ····_ARABIC_ISOLATED_FORM,
 12 ····_BASIC_LATIN_COMPATIBLE_RANGE_FAMILIES,
21 ····_CJK,13 ····_CJK,
 14 ····_COMPATIBLE_RANGE_FAMILIES,
 15 ····_COMPATIBLE_WITH_ANY_RANGE_FAMILIES,
22 ····_HANGUL,16 ····_HANGUL,
 17 ····_HALFWIDTH_KATAKANA,
23 ····_HIRAGANA,18 ····_HIRAGANA,
24 ····_KATAKANA,19 ····_KATAKANA,
25 ····_LATIN,20 ····_LATIN,
 21 ····_LIGATURE,
 22 ····_RANGE_FAMILIES,
 23 ····_SENTENCE_OPEN_PUNCTUATION,
 24 ····_SUPERSCRIPT,
26 ····_THAI,25 ····_THAI,
27 )26 )
28 from·.utils·import·(27 from·.utils·import·(
29 ····_character_flags,28 ····_character_flags,
30 ····is_emoticon,29 ····is_emoticon,
31 ····is_punctuation,30 ····is_punctuation,
32 ····is_separator,31 ····is_separator,
Offset 40, 15 lines modifiedOffset 37, 14 lines modified
40 ····unicode_range,37 ····unicode_range,
41 )38 )
  
42 #·Combined·bitmask·for·CJK/Hangul/Katakana/Hiragana/Thai·glyph·detection.39 #·Combined·bitmask·for·CJK/Hangul/Katakana/Hiragana/Thai·glyph·detection.
43 _GLYPH_MASK:·int·=·_CJK·|·_HANGUL·|·_KATAKANA·|·_HIRAGANA·|·_THAI40 _GLYPH_MASK:·int·=·_CJK·|·_HANGUL·|·_KATAKANA·|·_HIRAGANA·|·_THAI
  
  
44 @final 
45 class·CharInfo:41 class·CharInfo:
46 ····"""Pre-computed·character·properties·shared·across·all·detectors."""42 ····"""Pre-computed·character·properties·shared·across·all·detectors."""
  
47 ····__slots__·=·(43 ····__slots__·=·(
48 ········"character",44 ········"character",
49 ········"printable",45 ········"printable",
50 ········"alpha",46 ········"alpha",
Offset 58, 23 lines modifiedOffset 54, 29 lines modified
58 ········"digit",54 ········"digit",
59 ········"is_ascii",55 ········"is_ascii",
60 ········"case_variable",56 ········"case_variable",
61 ········"flags",57 ········"flags",
62 ········"accentuated",58 ········"accentuated",
63 ········"latin",59 ········"latin",
64 ········"is_cjk",60 ········"is_cjk",
 61 ········"is_katakana",
 62 ········"is_halfwidth_katakana",
65 ········"is_arabic",63 ········"is_arabic",
 64 ········"is_ligature",
 65 ········"is_superscript",
 66 ········"is_sentence_open_punctuation",
66 ········"is_glyph",67 ········"is_glyph",
67 ········"punct",68 ········"punct",
68 ········"sym",69 ········"sym",
69 ········"range",70 ········"range",
70 ········"sep",71 ········"sep",
71 ········"emoticon",72 ········"emoticon",
72 ········"safe",73 ········"safe",
73 ········"common_cjk",74 ········"common_cjk",
 75 ········"unaccented",
74 ····)76 ····)
  
75 ····character:·str77 ····character:·str
76 ····printable:·bool78 ····printable:·bool
77 ····alpha:·bool79 ····alpha:·bool
78 ····upper:·bool80 ····upper:·bool
79 ····lower:·bool81 ····lower:·bool
Offset 82, 37 lines modifiedOffset 84, 52 lines modified
82 ····digit:·bool84 ····digit:·bool
83 ····is_ascii:·bool85 ····is_ascii:·bool
84 ····case_variable:·bool86 ····case_variable:·bool
85 ····flags:·int87 ····flags:·int
86 ····accentuated:·bool88 ····accentuated:·bool
87 ····latin:·bool89 ····latin:·bool
88 ····is_cjk:·bool90 ····is_cjk:·bool
 91 ····is_katakana:·bool
 92 ····is_halfwidth_katakana:·bool
89 ····is_arabic:·bool93 ····is_arabic:·bool
 94 ····is_ligature:·bool
 95 ····is_superscript:·bool
 96 ····is_sentence_open_punctuation:·bool
90 ····is_glyph:·bool97 ····is_glyph:·bool
91 ····punct:·bool98 ····punct:·bool
92 ····sym:·bool99 ····sym:·bool
93 ····range:·str·|·None100 ····range:·str·|·None
94 ····sep:·bool101 ····sep:·bool
95 ····emoticon:·bool102 ····emoticon:·bool
96 ····safe:·bool103 ····safe:·bool
97 ····common_cjk:·bool104 ····common_cjk:·bool
 105 ····unaccented:·str
  
98 ····def·__init__(self,·character:·str)·->·None:106 ····def·__init__(self,·character:·str)·->·None:
99 ········"""Compute·all·properties·for·*character*·(built·once·per·codepoint,107 ········"""Compute·all·properties·for·*character*·(built·once·per·codepoint,
100 ········every·branch·assigns·every·slot)."""108 ········every·branch·assigns·every·slot)."""
101 ········self.character·=·character109 ········self.character·=·character
  
102 ········#·ASCII·fast-path:·for·characters·with·ord·<·128,·we·can·skip110 ········#·ASCII·fast-path:·for·characters·with·ord·<·128,·we·can·skip
103 ········#·_character_flags()·entirely·and·derive·most·properties·from·ord.111 ········#·_character_flags()·entirely·and·derive·most·properties·from·ord.
104 ········o:·int·=·ord(character)112 ········o:·int·=·ord(character)
105 ········if·o·<·128:113 ········if·o·<·128:
106 ············self.is_ascii·=·True114 ············self.is_ascii·=·True
107 ············self.accentuated·=·False115 ············self.accentuated·=·False
 116 ············self.unaccented·=·character
Max diff block lines reached; 28287/31487 bytes (89.84%) of diff not shown.
⊟
3.95 KB
charset_normalizer/models.py
    
Offset 36, 15 lines modifiedOffset 36, 19 lines modified
36 ········self._string:·str·|·None·=·decoded_payload36 ········self._string:·str·|·None·=·decoded_payload
  
37 ········self._preemptive_declaration:·str·|·None·=·preemptive_declaration37 ········self._preemptive_declaration:·str·|·None·=·preemptive_declaration
  
38 ····def·__eq__(self,·other:·object)·->·bool:38 ····def·__eq__(self,·other:·object)·->·bool:
39 ········if·not·isinstance(other,·CharsetMatch):39 ········if·not·isinstance(other,·CharsetMatch):
40 ············if·isinstance(other,·str):40 ············if·isinstance(other,·str):
 41 ················#·Use·non-strict·iana_name·so·an·operand·that·is·not·a·known
 42 ················#·encoding·alias·compares·unequal·instead·of·raising,·keeping
 43 ················#·__eq__·total·as·the·data·model·requires·(mirrors·the·lookup
 44 ················#·in·CharsetMatches.__getitem__).
41 ················return·iana_name(other)·==·self.encoding45 ················return·iana_name(other,·False)·==·self.encoding
42 ············return·False46 ············return·False
43 ········return·self.encoding·==·other.encoding·and·self.fingerprint·==·other.fingerprint47 ········return·self.encoding·==·other.encoding·and·self.fingerprint·==·other.fingerprint
  
44 ····def·__lt__(self,·other:·object)·->·bool:48 ····def·__lt__(self,·other:·object)·->·bool:
45 ········"""49 ········"""
46 ········Implemented·to·make·sorted·available·upon·CharsetMatches·items.50 ········Implemented·to·make·sorted·available·upon·CharsetMatches·items.
47 ········"""51 ········"""
Offset 64, 15 lines modifiedOffset 68, 19 lines modified
64 ················return·self.chaos·<·other.chaos68 ················return·self.chaos·<·other.chaos
65 ············return·self.multi_byte_usage·>·other.multi_byte_usage69 ············return·self.multi_byte_usage·>·other.multi_byte_usage
  
66 ········return·self.chaos·<·other.chaos70 ········return·self.chaos·<·other.chaos
  
67 ····@property71 ····@property
68 ····def·multi_byte_usage(self)·->·float:72 ····def·multi_byte_usage(self)·->·float:
 73 ········#·Empty·payloads·are·valid·(from_bytes(b"")·returns·a·match);·avoid·/0.
 74 ········raw_len·=·len(self.raw)
 75 ········if·raw_len·==·0:
 76 ············return·0.0
69 ········return·1.0·-·(len(str(self))·/·len(self.raw))77 ········return·1.0·-·(len(str(self))·/·raw_len)
  
70 ····def·__str__(self)·->·str:78 ····def·__str__(self)·->·str:
71 ········#·Lazy·Str·Loading79 ········#·Lazy·Str·Loading
72 ········if·self._string·is·None:80 ········if·self._string·is·None:
73 ············self._string·=·str(self._payload,·self._encoding,·"strict")81 ············self._string·=·str(self._payload,·self._encoding,·"strict")
74 ············#·UTF-7·BOM·is·encoded·in·modified·Base64·whose·byte·boundary82 ············#·UTF-7·BOM·is·encoded·in·modified·Base64·whose·byte·boundary
75 ············#·can·overlap·with·the·next·character,·so·raw-byte·stripping83 ············#·can·overlap·with·the·next·character,·so·raw-byte·stripping
Offset 254, 24 lines modifiedOffset 262, 32 lines modified
254 ····"""262 ····"""
255 ····Container·with·every·CharsetMatch·items·ordered·by·default·from·most·probable·to·the·less·one.263 ····Container·with·every·CharsetMatch·items·ordered·by·default·from·most·probable·to·the·less·one.
256 ····Act·like·a·list(iterable)·but·does·not·implements·all·related·methods.264 ····Act·like·a·list(iterable)·but·does·not·implements·all·related·methods.
257 ····"""265 ····"""
  
258 ····def·__init__(self,·results:·list[CharsetMatch]·|·None·=·None):266 ····def·__init__(self,·results:·list[CharsetMatch]·|·None·=·None):
259 ········self._results:·list[CharsetMatch]·=·sorted(results)·if·results·else·[]267 ········self._results:·list[CharsetMatch]·=·sorted(results)·if·results·else·[]
 268 ········self._is_sorted:·bool·=·True
  
 269 ····def·_ensure_sorted(self)·->·None:
 270 ········if·not·self._is_sorted:
 271 ············self._results.sort()
 272 ············self._is_sorted·=·True
  
260 ····def·__iter__(self)·->·Iterator[CharsetMatch]:273 ····def·__iter__(self)·->·Iterator[CharsetMatch]:
 274 ········self._ensure_sorted()
261 ········yield·from·self._results275 ········yield·from·self._results
  
262 ····def·__getitem__(self,·item:·int·|·str)·->·CharsetMatch:276 ····def·__getitem__(self,·item:·int·|·str)·->·CharsetMatch:
263 ········"""277 ········"""
264 ········Retrieve·a·single·item·either·by·its·position·or·encoding·name·(alias·may·be·used·here).278 ········Retrieve·a·single·item·either·by·its·position·or·encoding·name·(alias·may·be·used·here).
265 ········Raise·KeyError·upon·invalid·index·or·encoding·not·present·in·results.279 ········Raise·KeyError·upon·invalid·index·or·encoding·not·present·in·results.
266 ········"""280 ········"""
267 ········if·isinstance(item,·int):281 ········if·isinstance(item,·int):
 282 ············self._ensure_sorted()
268 ············return·self._results[item]283 ············return·self._results[item]
269 ········if·isinstance(item,·str):284 ········if·isinstance(item,·str):
270 ············item·=·iana_name(item,·False)285 ············item·=·iana_name(item,·False)
271 ············for·result·in·self._results:286 ············for·result·in·self._results:
272 ················if·item·in·result.could_be_from_charset:287 ················if·item·in·result.could_be_from_charset:
273 ····················return·result288 ····················return·result
274 ········raise·KeyError289 ········raise·KeyError
Offset 296, 22 lines modifiedOffset 312, 23 lines modified
296 ········#·We·should·disable·the·submatch·factoring·when·the·input·file·is·too·heavy·(conserve·RAM·usage)312 ········#·We·should·disable·the·submatch·factoring·when·the·input·file·is·too·heavy·(conserve·RAM·usage)
297 ········if·len(item.raw)·<·TOO_BIG_SEQUENCE:313 ········if·len(item.raw)·<·TOO_BIG_SEQUENCE:
298 ············for·match·in·self._results:314 ············for·match·in·self._results:
299 ················if·match.fingerprint·==·item.fingerprint·and·match.chaos·==·item.chaos:315 ················if·match.fingerprint·==·item.fingerprint·and·match.chaos·==·item.chaos:
300 ····················match.add_submatch(item)316 ····················match.add_submatch(item)
301 ····················return317 ····················return
302 ········self._results.append(item)318 ········self._results.append(item)
303 ········self._results·=·sorted(self._results)319 ········self._is_sorted·=·False
  
304 ····def·best(self)·->·CharsetMatch·|·None:320 ····def·best(self)·->·CharsetMatch·|·None:
305 ········"""321 ········"""
306 ········Simply·return·the·first·match.·Strict·equivalent·to·matches[0].322 ········Simply·return·the·first·match.·Strict·equivalent·to·matches[0].
307 ········"""323 ········"""
308 ········if·not·self._results:324 ········if·not·self._results:
309 ············return·None325 ············return·None
 326 ········self._ensure_sorted()
310 ········return·self._results[0]327 ········return·self._results[0]
  
311 ····def·first(self)·->·CharsetMatch·|·None:328 ····def·first(self)·->·CharsetMatch·|·None:
312 ········"""329 ········"""
313 ········Redundant·method,·call·the·method·best().·Kept·for·BC·reasons.330 ········Redundant·method,·call·the·method·best().·Kept·for·BC·reasons.
314 ········"""331 ········"""
315 ········return·self.best()332 ········return·self.best()
⊟
11.4 KB
charset_normalizer/utils.py
    
Offset 1, 37 lines modifiedOffset 1, 42 lines modified
1 from·__future__·import·annotations1 from·__future__·import·annotations
  
2 import·importlib2 import·importlib
3 import·logging3 import·logging
4 import·unicodedata4 import·unicodedata
5 from·bisect·import·bisect_right5 from·bisect·import·bisect_right
6 from·codecs·import·IncrementalDecoder6 from·codecs·import·IncrementalDecoder
7 from·encodings.aliases·import·aliases 
8 from·functools·import·lru_cache7 from·functools·import·lru_cache
9 from·re·import·findall 
10 from·typing·import·Generator8 from·typing·import·Generator
  
11 from·.constant·import·(9 from·.constant·import·(
12 ····ENCODING_MARKS,10 ····ENCODING_MARKS,
13 ····IANA_SUPPORTED_SIMILAR,11 ····IANA_SUPPORTED_SIMILAR,
14 ····RE_POSSIBLE_ENCODING_INDICATION,12 ····RE_POSSIBLE_ENCODING_INDICATION,
15 ····UNICODE_RANGES_COMBINED,13 ····UNICODE_RANGES_COMBINED,
16 ····_SECONDARY_RANGE_NAMES,14 ····_SECONDARY_RANGE_NAMES,
17 ····UTF8_MAXIMAL_ALLOCATION, 
18 ····COMMON_CJK_CHARACTERS,15 ····COMMON_CJK_CHARACTERS,
19 ····_LATIN,16 ····_LATIN,
20 ····_CJK,17 ····_CJK,
21 ····_HANGUL,18 ····_HANGUL,
22 ····_KATAKANA,19 ····_KATAKANA,
23 ····_HIRAGANA,20 ····_HIRAGANA,
 21 ····_HALFWIDTH_KATAKANA,
24 ····_THAI,22 ····_THAI,
25 ····_ARABIC,23 ····_ARABIC,
26 ····_ARABIC_ISOLATED_FORM,24 ····_ARABIC_ISOLATED_FORM,
 25 ····_LIGATURE,
 26 ····_SUPERSCRIPT,
 27 ····_SENTENCE_OPEN_PUNCTUATION,
27 ····_ACCENT_KEYWORDS,28 ····_ACCENT_KEYWORDS,
28 ····_ACCENTUATED,29 ····_ACCENTUATED,
 30 ····_KNOWN_MB_DECODERS,
 31 ····_KNOWN_MB_CLASSES,
 32 ····_IANA_NAMES,
 33 ····_MULTIBYTE_SEARCH_RADIUS,
29 )34 )
  
  
30 def·_character_flags(character:·str)·->·int:35 def·_character_flags(character:·str)·->·int:
31 ····"""Compute·all·name-based·classification·flags·with·a·single·unicodedata.name()·call."""36 ····"""Compute·all·name-based·classification·flags·with·a·single·unicodedata.name()·call."""
32 ····try:37 ····try:
33 ········desc:·str·=·unicodedata.name(character)38 ········desc:·str·=·unicodedata.name(character)
Offset 44, 36 lines modifiedOffset 49, 43 lines modified
44 ········flags·|=·_LATIN49 ········flags·|=·_LATIN
45 ····if·"CJK"·in·desc:50 ····if·"CJK"·in·desc:
46 ········flags·|=·_CJK51 ········flags·|=·_CJK
47 ····if·"HANGUL"·in·desc:52 ····if·"HANGUL"·in·desc:
48 ········flags·|=·_HANGUL53 ········flags·|=·_HANGUL
49 ····if·"KATAKANA"·in·desc:54 ····if·"KATAKANA"·in·desc:
50 ········flags·|=·_KATAKANA55 ········flags·|=·_KATAKANA
 56 ········if·"HALFWIDTH"·in·desc:
 57 ············flags·|=·_HALFWIDTH_KATAKANA
51 ····if·"HIRAGANA"·in·desc:58 ····if·"HIRAGANA"·in·desc:
52 ········flags·|=·_HIRAGANA59 ········flags·|=·_HIRAGANA
53 ····if·"THAI"·in·desc:60 ····if·"THAI"·in·desc:
54 ········flags·|=·_THAI61 ········flags·|=·_THAI
55 ····if·"ARABIC"·in·desc:62 ····if·"ARABIC"·in·desc:
56 ········flags·|=·_ARABIC63 ········flags·|=·_ARABIC
57 ········if·"ISOLATED·FORM"·in·desc:64 ········if·"ISOLATED·FORM"·in·desc:
58 ············flags·|=·_ARABIC_ISOLATED_FORM65 ············flags·|=·_ARABIC_ISOLATED_FORM
 66 ····if·"LIGATURE"·in·desc·or·desc.endswith("LETTER·AE"):
 67 ········flags·|=·_LIGATURE
 68 ····if·"SUPERSCRIPT"·in·desc:
 69 ········flags·|=·_SUPERSCRIPT
 70 ····if·desc·in·{"INVERTED·QUESTION·MARK",·"INVERTED·EXCLAMATION·MARK"}:
 71 ········flags·|=·_SENTENCE_OPEN_PUNCTUATION
  
59 ····for·kw·in·_ACCENT_KEYWORDS:72 ····for·kw·in·_ACCENT_KEYWORDS:
60 ········if·kw·in·desc:73 ········if·kw·in·desc:
61 ············flags·|=·_ACCENTUATED74 ············flags·|=·_ACCENTUATED
62 ············break75 ············break
  
63 ····return·flags76 ····return·flags
  
  
64 def·is_accentuated(character:·str)·->·bool:77 def·is_accentuated(character:·str)·->·bool:
65 ····return·bool(_character_flags(character)·&·_ACCENTUATED)78 ····return·bool(_character_flags(character)·&·_ACCENTUATED)
  
  
66 @lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) 
67 def·remove_accent(character:·str)·->·str:79 def·remove_accent(character:·str)·->·str:
68 ····decomposed:·str·=·unicodedata.decomposition(character)80 ····decomposed:·str·=·unicodedata.decomposition(character)
69 ····if·not·decomposed:81 ····if·not·decomposed:
70 ········return·character82 ········return·character
  
71 ····codes:·list[str]·=·decomposed.split("·")83 ····codes:·list[str]·=·decomposed.split("·")
  
Offset 91, 14 lines modifiedOffset 103, 19 lines modified
  
91 def·unicode_range(character:·str)·->·str·|·None:103 def·unicode_range(character:·str)·->·str·|·None:
92 ····"""104 ····"""
93 ····Retrieve·the·Unicode·range·official·name·from·a·single·character.105 ····Retrieve·the·Unicode·range·official·name·from·a·single·character.
94 ····"""106 ····"""
95 ····character_ord:·int·=·ord(character)107 ····character_ord:·int·=·ord(character)
  
 108 ····if·character_ord·<·32:
 109 ········return·"Control·character"
 110 ····if·character_ord·<·128:
 111 ········return·"Basic·Latin"
  
96 ····#·Binary·search:·find·the·rightmost·range·whose·start·<=·character_ord112 ····#·Binary·search:·find·the·rightmost·range·whose·start·<=·character_ord
97 ····idx·=·bisect_right(_UNICODE_RANGE_STARTS,·character_ord)·-·1113 ····idx·=·bisect_right(_UNICODE_RANGE_STARTS,·character_ord)·-·1
98 ····if·idx·>=·0:114 ····if·idx·>=·0:
99 ········start,·stop,·name·=·_UNICODE_RANGES_SORTED[idx]115 ········start,·stop,·name·=·_UNICODE_RANGES_SORTED[idx]
100 ········if·character_ord·<·stop:116 ········if·character_ord·<·stop:
101 ············return·name117 ············return·name
  
Offset 151, 64 lines modifiedOffset 168, 54 lines modified
151 ········return·True168 ········return·True
  
152 ····character_category:·str·=·unicodedata.category(character)169 ····character_category:·str·=·unicodedata.category(character)
  
153 ····return·"Z"·in·character_category·or·character_category·in·{"Po",·"Pd",·"Pc"}170 ····return·"Z"·in·character_category·or·character_category·in·{"Po",·"Pd",·"Pc"}
  
  
154 @lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) 
155 def·is_case_variable(character:·str)·->·bool:171 def·is_case_variable(character:·str)·->·bool:
156 ····return·character.islower()·!=·character.isupper()172 ····return·character.islower()·!=·character.isupper()
  
  
157 @lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) 
158 def·is_cjk(character:·str)·->·bool:173 def·is_cjk(character:·str)·->·bool:
159 ····return·bool(_character_flags(character)·&·_CJK)174 ····return·bool(_character_flags(character)·&·_CJK)
  
Max diff block lines reached; 8112/11582 bytes (70.04%) of diff not shown.
⊟
220 B
charset_normalizer/version.py
    
Offset 1, 8 lines modifiedOffset 1, 8 lines modified
1 """1 """
2 Expose·version2 Expose·version
3 """3 """
  
4 from·__future__·import·annotations4 from·__future__·import·annotations
  
5 __version__·=·"3.4.9"5 __version__·=·"3.5.2"
6 VERSION·=·__version__.split(".")6 VERSION·=·__version__.split(".")
⊟
569 B
cssselect2/__init__.py
    
Offset 9, 15 lines modifiedOffset 9, 15 lines modified
9 from·webencodings·import·ascii_lower9 from·webencodings·import·ascii_lower
  
10 #·Classes·are·imported·here·to·expose·them·at·the·top·level·of·the·module10 #·Classes·are·imported·here·to·expose·them·at·the·top·level·of·the·module
11 from·.compiler·import·compile_selector_list··#·noqa11 from·.compiler·import·compile_selector_list··#·noqa
12 from·.parser·import·SelectorError··#·noqa12 from·.parser·import·SelectorError··#·noqa
13 from·.tree·import·ElementWrapper··#·noqa13 from·.tree·import·ElementWrapper··#·noqa
  
14 VERSION·=·__version__·=·'0.9.0'14 VERSION·=·__version__·=·'0.10.1'
  
  
15 class·Matcher:15 class·Matcher:
16 ····"""A·CSS·selectors·storage·that·can·match·against·HTML·elements."""16 ····"""A·CSS·selectors·storage·that·can·match·against·HTML·elements."""
17 ····def·__init__(self):17 ····def·__init__(self):
18 ········self.id_selectors·=·{}18 ········self.id_selectors·=·{}
19 ········self.class_selectors·=·{}19 ········self.class_selectors·=·{}
⊟
711 B
cssselect2/parser.py
    
Offset 5, 14 lines modifiedOffset 5, 16 lines modified
5 SUPPORTED_PSEUDO_ELEMENTS·=·{5 SUPPORTED_PSEUDO_ELEMENTS·=·{
6 ····#·As·per·CSS·Pseudo-Elements·Module·Level·46 ····#·As·per·CSS·Pseudo-Elements·Module·Level·4
7 ····'first-line',·'first-letter',·'prefix',·'postfix',·'selection',7 ····'first-line',·'first-letter',·'prefix',·'postfix',·'selection',
8 ····'target-text',·'spelling-error',·'grammar-error',·'before',·'after',8 ····'target-text',·'spelling-error',·'grammar-error',·'before',·'after',
9 ····'marker',·'placeholder',·'file-selector-button',9 ····'marker',·'placeholder',·'file-selector-button',
10 ····#·As·per·CSS·Generated·Content·for·Paged·Media·Module10 ····#·As·per·CSS·Generated·Content·for·Paged·Media·Module
11 ····'footnote-call',·'footnote-marker',11 ····'footnote-call',·'footnote-marker',
 12 ····#·As·per·CSS·Notes
 13 ····'note-call',·'note-marker',·'note-callback',
12 ····#·As·per·CSS·Scoping·Module·Level·114 ····#·As·per·CSS·Scoping·Module·Level·1
13 ····'content',·'shadow',15 ····'content',·'shadow',
14 }16 }
  
  
15 def·parse(input,·namespaces=None,·forgiving=False,·relative=False):17 def·parse(input,·namespaces=None,·forgiving=False,·relative=False):
16 ····"""Yield·tinycss2·selectors·found·in·given·``input``.18 ····"""Yield·tinycss2·selectors·found·in·given·``input``.
⊟
3.36 KB
filelock/__init__.py
    
Offset 1, 26 lines modifiedOffset 1, 30 lines modified
1 """1 """
2 A·platform·independent·file·lock·that·supports·the·with-statement.2 A·platform·independent·file·lock·that·supports·the·with-statement.
  
3 ..·autodata::·filelock.__version__3 ..·autodata::·filelock.__version__
4 ····:no-value:4 ····:no-value:
  
 5 ..·autodata::·filelock.OwnerMode
  
 6 ..·autodata::·filelock.CompromiseReason
  
5 """7 """
  
6 from·__future__·import·annotations8 from·__future__·import·annotations
  
7 import·sys9 import·sys
8 import·warnings10 import·warnings
9 from·typing·import·TYPE_CHECKING,·Final11 from·typing·import·TYPE_CHECKING,·Final
  
10 from·._api·import·AcquireReturnProxy,·BaseFileLock,·CloseErrorPolicy,·ContextErrorPolicy,·LockOptions12 from·._api·import·AcquireReturnProxy,·BaseFileLock,·CloseErrorPolicy,·ContextErrorPolicy,·LockOptions
11 from·._descriptor·import·lock_descriptor,·unlock_descriptor13 from·._descriptor·import·lock_descriptor,·unlock_descriptor
12 from·._error·import·LeaseSettingsMismatch,·SoftFileLockLifetimeWarning,·SoftFileLockProtocolError,·Timeout14 from·._error·import·LeaseSettingsMismatch,·SoftFileLockLifetimeWarning,·SoftFileLockProtocolError,·Timeout
13 from·._lease·import·LeaseCompromise,·SoftFileLease15 from·._lease·import·CompromiseReason,·LeaseCompromise,·SoftFileLease
14 from·._marker·import·MarkerSoftFileLock,·OwnerRecord16 from·._marker·import·MarkerSoftFileLock,·OwnerMode,·OwnerRecord
  
15 if·TYPE_CHECKING:17 if·TYPE_CHECKING:
16 ····from·._async_read_write·import·(18 ····from·._async_read_write·import·(
17 ········AsyncAcquireReadWriteReturnProxy,19 ········AsyncAcquireReadWriteReturnProxy,
18 ········AsyncReadWriteLock,20 ········AsyncReadWriteLock,
19 ····)21 ····)
20 ····from·._read_write·import·ReadWriteLock22 ····from·._read_write·import·ReadWriteLock
Offset 32, 30 lines modifiedOffset 36, 39 lines modified
32 ········AsyncAcquireReadWriteReturnProxy·=·None36 ········AsyncAcquireReadWriteReturnProxy·=·None
33 ········AsyncReadWriteLock·=·None37 ········AsyncReadWriteLock·=·None
34 ········ReadWriteLock·=·None38 ········ReadWriteLock·=·None
  
35 from·._soft·import·SoftFileLock39 from·._soft·import·SoftFileLock
36 from·._soft_rw·import·AsyncAcquireSoftReadWriteReturnProxy,·AsyncSoftReadWriteLock,·SoftReadWriteLock40 from·._soft_rw·import·AsyncAcquireSoftReadWriteReturnProxy,·AsyncSoftReadWriteLock,·SoftReadWriteLock
37 from·._strict·import·StrictSoftFileClaim,·StrictSoftFileClaimState,·StrictSoftFileLock41 from·._strict·import·StrictSoftFileClaim,·StrictSoftFileClaimState,·StrictSoftFileLock
38 from·._unix·import·UnixFileLock,·has_fcntl42 from·._unix·import·UnixFileLock
 43 from·._unix·import·has_fcntl·as·_has_fcntl
39 from·._windows·import·WindowsFileLock44 from·._windows·import·WindowsFileLock
40 from·.asyncio·import·(45 from·.asyncio·import·(
41 ····AsyncAcquireReturnProxy,46 ····AsyncAcquireReturnProxy,
42 ····AsyncSoftFileLease,47 ····AsyncSoftFileLease,
43 ····AsyncSoftFileLock,48 ····AsyncSoftFileLock,
44 ····AsyncStrictSoftFileLock,49 ····AsyncStrictSoftFileLock,
45 ····AsyncUnixFileLock,50 ····AsyncUnixFileLock,
46 ····AsyncWindowsFileLock,51 ····AsyncWindowsFileLock,
47 ····BaseAsyncFileLock,52 ····BaseAsyncFileLock,
48 )53 )
  
 54 #·Keeps·``filelock.version``·the·string·4.0.12·exposed·rather·than·the·submodule.
49 from·.version·import·version55 from·.version·import·version
  
50 #:·version·of·the·project·as·a·string56 #:·version·of·the·project·as·a·string
51 __version__:·Final[str]·=·version57 __version__:·Final[str]·=·version
  
 58 #:·``True``·when·:func:`fcntl.flock`·is·available.·Off·Windows,·:data:`FileLock`·then·resolves·to
 59 #:·:class:`UnixFileLock`,·otherwise·to·:class:`SoftFileLock`.·Always·``False``·on·Windows.
 60 #:
 61 #:·:meta·hide-value:
 62 has_fcntl:·Final[bool]·=·_has_fcntl
  
  
52 if·sys.platform·==·"win32":··#·pragma:·win32·cover63 if·sys.platform·==·"win32":··#·pragma:·win32·cover
53 ····_FileLock:·type[BaseFileLock]·=·WindowsFileLock64 ····_FileLock:·type[BaseFileLock]·=·WindowsFileLock
54 ····_AsyncFileLock:·type[BaseAsyncFileLock]·=·AsyncWindowsFileLock65 ····_AsyncFileLock:·type[BaseAsyncFileLock]·=·AsyncWindowsFileLock
55 else:··#·pragma:·win32·no·cover·#·ruff:ignore[collapsible-else-if]··#·the·else·carries·the·win32·no-cover·pragma66 else:··#·pragma:·win32·no·cover·#·ruff:ignore[collapsible-else-if]··#·the·else·carries·the·win32·no-cover·pragma
56 ····if·has_fcntl:67 ····if·has_fcntl:
57 ········_FileLock:·type[BaseFileLock]·=·UnixFileLock68 ········_FileLock:·type[BaseFileLock]·=·UnixFileLock
Offset 86, 30 lines modifiedOffset 99, 33 lines modified
86 ····"AsyncSoftReadWriteLock",99 ····"AsyncSoftReadWriteLock",
87 ····"AsyncStrictSoftFileLock",100 ····"AsyncStrictSoftFileLock",
88 ····"AsyncUnixFileLock",101 ····"AsyncUnixFileLock",
89 ····"AsyncWindowsFileLock",102 ····"AsyncWindowsFileLock",
90 ····"BaseAsyncFileLock",103 ····"BaseAsyncFileLock",
91 ····"BaseFileLock",104 ····"BaseFileLock",
92 ····"CloseErrorPolicy",105 ····"CloseErrorPolicy",
 106 ····"CompromiseReason",
93 ····"ContextErrorPolicy",107 ····"ContextErrorPolicy",
94 ····"FileLock",108 ····"FileLock",
95 ····"LeaseCompromise",109 ····"LeaseCompromise",
96 ····"LeaseSettingsMismatch",110 ····"LeaseSettingsMismatch",
97 ····"LockOptions",111 ····"LockOptions",
98 ····"MarkerSoftFileLock",112 ····"MarkerSoftFileLock",
 113 ····"OwnerMode",
99 ····"OwnerRecord",114 ····"OwnerRecord",
100 ····"ReadWriteLock",115 ····"ReadWriteLock",
101 ····"SoftFileLease",116 ····"SoftFileLease",
102 ····"SoftFileLock",117 ····"SoftFileLock",
103 ····"SoftFileLockLifetimeWarning",118 ····"SoftFileLockLifetimeWarning",
104 ····"SoftFileLockProtocolError",119 ····"SoftFileLockProtocolError",
105 ····"SoftReadWriteLock",120 ····"SoftReadWriteLock",
106 ····"StrictSoftFileClaim",121 ····"StrictSoftFileClaim",
107 ····"StrictSoftFileClaimState",122 ····"StrictSoftFileClaimState",
108 ····"StrictSoftFileLock",123 ····"StrictSoftFileLock",
109 ····"Timeout",124 ····"Timeout",
110 ····"UnixFileLock",125 ····"UnixFileLock",
111 ····"WindowsFileLock",126 ····"WindowsFileLock",
112 ····"__version__",127 ····"__version__",
 128 ····"has_fcntl",
113 ····"lock_descriptor",129 ····"lock_descriptor",
114 ····"unlock_descriptor",130 ····"unlock_descriptor",
115 ]131 ]
⊟
77.9 KB
filelock/_api.py
    
Offset 2, 49 lines modifiedOffset 2, 57 lines modified
  
2 import·contextlib2 import·contextlib
3 import·inspect3 import·inspect
4 import·logging4 import·logging
5 import·math5 import·math
6 import·os6 import·os
7 import·secrets7 import·secrets
 8 import·stat
8 import·sys9 import·sys
9 import·time10 import·time
10 import·warnings11 import·warnings
11 from·abc·import·ABCMeta,·abstractmethod12 from·abc·import·ABCMeta,·abstractmethod
12 from·collections.abc·import·Callable,·Hashable13 from·collections.abc·import·Callable,·Hashable
13 from·contextlib·import·contextmanager14 from·contextlib·import·contextmanager
14 from·dataclasses·import·dataclass15 from·dataclasses·import·dataclass,·fields
 16 from·decimal·import·Decimal
15 from·itertools·import·count,·starmap17 from·itertools·import·count,·starmap
 18 from·numbers·import·Real
16 from·threading·import·Condition,·RLock,·get_ident,·local19 from·threading·import·TIMEOUT_MAX,·Condition,·RLock,·Thread,·current_thread,·get_ident,·local
17 from·typing·import·TYPE_CHECKING,·Final,·Literal,·NoReturn,·TypedDict,·TypeVar,·cast20 from·typing·import·TYPE_CHECKING,·Final,·Generic,·Literal,·NoReturn,·TypedDict,·TypeVar,·cast
18 from·weakref·import·WeakKeyDictionary,·WeakValueDictionary21 from·weakref·import·WeakKeyDictionary,·WeakValueDictionary
  
19 from·._error·import·SoftFileLockLifetimeWarning,·Timeout22 from·._error·import·SoftFileLockLifetimeWarning,·Timeout
20 from·._util·import·break_lock_file23 from·._util·import·break_lock_file
  
21 #:·No·explicit·file·permission·mode·was·passed.·Lock·files·then·open·with·0o666·so·umask·and·default·ACLs·pick24 #:·No·explicit·file·permission·mode·was·passed.·Lock·files·then·open·with·0o666·so·umask·and·default·ACLs·pick
22 #:·the·final·permissions,·and·fchmod·is·skipped·to·preserve·POSIX·default·ACL·inheritance.25 #:·the·final·permissions,·and·fchmod·is·skipped·to·preserve·POSIX·default·ACL·inheritance.
23 _UNSET_FILE_MODE:·Final[int]·=·-126 _UNSET_FILE_MODE:·Final[int]·=·-1
  
 27 _PERMISSION_BITS:·Final[int]·=·stat.S_IRWXU·|·stat.S_IRWXG·|·stat.S_IRWXO
  
24 #:·Ceiling·on·the·retry·counter·used·as·a·power·of·two,·so·a·long·contended·wait·cannot·overflow·the·backoff·multiply.28 #:·Ceiling·on·the·retry·counter·used·as·a·power·of·two,·so·a·long·contended·wait·cannot·overflow·the·backoff·multiply.
25 _MAX_BACKOFF_EXPONENT:·Final[int]·=·2029 _MAX_BACKOFF_EXPONENT:·Final[int]·=·20
  
26 #:·How·a·context·manager·reconciles·a·body·failure·with·a·release·failure·on·exit·(see·the·property·of·this·name).30 #:·How·a·context·manager·reconciles·a·body·failure·with·a·release·failure·on·exit·(see·the·property·of·this·name).
27 ContextErrorPolicy·=·Literal["chain",·"group"]31 ContextErrorPolicy·=·Literal["chain",·"group"]
28 _CONTEXT_ERROR_POLICIES:·Final[frozenset[str]]·=·frozenset({"chain",·"group"})32 _CONTEXT_ERROR_POLICIES:·Final[frozenset[str]]·=·frozenset({"chain",·"group"})
  
29 #:·What·a·descriptor-owning·backend·does·with·an·``os.close``·failure·after·relinquishing·ownership·(see·the·property).33 #:·What·a·descriptor-owning·backend·does·with·an·``os.close``·failure·after·relinquishing·ownership·(see·the·property).
30 CloseErrorPolicy·=·Literal["default",·"raise",·"suppress"]34 CloseErrorPolicy·=·Literal["default",·"raise",·"suppress"]
31 _CLOSE_ERROR_POLICIES:·Final[frozenset[str]]·=·frozenset({"default",·"raise",·"suppress"})35 _CLOSE_ERROR_POLICIES:·Final[frozenset[str]]·=·frozenset({"default",·"raise",·"suppress"})
  
32 if·TYPE_CHECKING:36 if·TYPE_CHECKING:
33 ····from·collections.abc·import·Generator37 ····from·collections.abc·import·Generator,·Mapping
34 ····from·types·import·TracebackType38 ····from·types·import·FrameType,·TracebackType
35 ····from·typing·import·Protocol39 ····from·typing·import·Protocol
  
 40 ····from·_typeshed·import·Unused
  
 41 ····from·._lease·import·_LeaseClaim
36 ····from·._read_write·import·ReadWriteLock42 ····from·._read_write·import·ReadWriteLock
37 ····from·._soft_rw·import·SoftReadWriteLock43 ····from·._soft_rw·import·SoftReadWriteLock
  
38 ····class·_ForkResettable(Protocol):44 ····class·_ForkResettable(Protocol):
39 ········def·_reset_after_fork_in_child(self)·->·None:·...45 ········def·_reset_after_fork_in_child(self)·->·None:·...
  
40 ····class·_ForkDescriptorOwner(Protocol):46 ····class·_ForkDescriptorOwner(Protocol):
Offset 60, 18 lines modifiedOffset 68, 15 lines modified
60 ············self,68 ············self,
61 ············*,69 ············*,
62 ············before:·Callable[[],·None]·|·None·=·None,70 ············before:·Callable[[],·None]·|·None·=·None,
63 ············after_in_parent:·Callable[[],·None]·|·None·=·None,71 ············after_in_parent:·Callable[[],·None]·|·None·=·None,
64 ············after_in_child:·Callable[[],·None]·|·None·=·None,72 ············after_in_child:·Callable[[],·None]·|·None·=·None,
65 ········)·->·None:·...73 ········)·->·None:·...
  
66 ····if·sys.version_info·>=·(3,·11):··#·pragma:·no·cover·(py311+) 
67 ········from·typing·import·Self74 ····from·typing·import·Self
68 ····else:··#·pragma:·no·cover·(<py311) 
69 ········from·typing_extensions·import·Self 
  
70 _LOGGER:·Final[logging.Logger]·=·logging.getLogger("filelock")75 _LOGGER:·Final[logging.Logger]·=·logging.getLogger("filelock")
71 _REGISTER_AT_FORK:·Final[_RegisterAtFork·|·None]·=·cast("_RegisterAtFork·|·None",·getattr(os,·"register_at_fork",·None))76 _REGISTER_AT_FORK:·Final[_RegisterAtFork·|·None]·=·cast("_RegisterAtFork·|·None",·getattr(os,·"register_at_fork",·None))
72 _HAS_REGISTER_AT_FORK:·Final[bool]·=·_REGISTER_AT_FORK·is·not·None77 _HAS_REGISTER_AT_FORK:·Final[bool]·=·_REGISTER_AT_FORK·is·not·None
  
73 _ExtraValue·=·TypeVar("_ExtraValue")78 _ExtraValue·=·TypeVar("_ExtraValue")
74 _MarkerValue·=·TypeVar("_MarkerValue")79 _MarkerValue·=·TypeVar("_MarkerValue")
Offset 92, 37 lines modifiedOffset 97, 28 lines modified
92 ····context_error_policy:·ContextErrorPolicy97 ····context_error_policy:·ContextErrorPolicy
93 ····close_error_policy:·CloseErrorPolicy98 ····close_error_policy:·CloseErrorPolicy
94 ····fallback_to_soft:·bool99 ····fallback_to_soft:·bool
95 ····preserve_lock_file:·bool100 ····preserve_lock_file:·bool
96 ····on_acquired:·Callable[[int],·None]·|·None101 ····on_acquired:·Callable[[int],·None]·|·None
  
  
 102 def·_is_exception_group(error:·BaseException)·->·bool:
 103 ····return·isinstance(error,·BaseExceptionGroup)
97 def·_exception_group_cls()·->·type[BaseException]: 
98 ····#·BaseExceptionGroup·is·a·builtin·on·3.11+;·on·3.10·it·needs·the·exceptiongroup·backport.·filelock·keeps·zero 
99 ····#·runtime·dependencies,·so·the·backport·is·imported·lazily·rather·than·required,·and·only·group·mode·needs·it. 
100 ····if·sys.version_info·>=·(3,·11):··#·pragma:·no·cover·(py311+) 
101 ········return·BaseExceptionGroup··#·ruff:ignore[undefined-name]··#·builtin·on·3.11+ 
102 ····#·Alias·the·import·so·BaseExceptionGroup·above·stays·the·builtin·rather·than·an·unbound·local·of·this·function. 
103 ····from·exceptiongroup·import·(··#·ruff:ignore[import-outside-top-level]··#·pragma:·no·cover·(<py311) 
104 ········BaseExceptionGroup·as·_Backport, 
105 ····) 
  
106 ····return·_Backport··#·pragma:·no·cover·(<py311) 
  
  
107 def·_raise_grouped_errors(104 def·_raise_grouped_errors(
108 ····message:·str,105 ····message:·str,
109 ····first_error:·BaseException,106 ····first_error:·BaseException,
110 ····second_error:·BaseException,107 ····second_error:·BaseException,
111 ····*additional_errors:·BaseException,108 ····*additional_errors:·BaseException,
112 ····marker:·tuple[str,·_MarkerValue]·|·None·=·None,109 ····marker:·tuple[str,·_MarkerValue]·|·None·=·None,
113 )·->·NoReturn:110 )·->·NoReturn:
114 ····errors·=·(first_error,·second_error,·*additional_errors)111 ····errors·=·(first_error,·second_error,·*additional_errors)
115 ····_detach_grouped_contexts(errors)112 ····_detach_grouped_contexts(errors)
116 ····group·=·_exception_group_cls()(message,·errors)113 ····group:·Final·=·BaseExceptionGroup(message,·errors)
117 ····if·marker·is·not·None:114 ····if·marker·is·not·None:
118 ········setattr(group,·marker[0],·marker[1])115 ········setattr(group,·marker[0],·marker[1])
119 ····raise·group·from·None116 ····raise·group·from·None
  
  
120 def·_detach_grouped_contexts(errors:·tuple[BaseException,·...])·->·None:117 def·_detach_grouped_contexts(errors:·tuple[BaseException,·...])·->·None:
121 ····seen:·set[int]·=·set()118 ····seen:·set[int]·=·set()
Offset 138, 15 lines modifiedOffset 134, 15 lines modified
138 ············or·any(context·is·root·or·_contains_exception(root,·context)·for·root·in·errors)134 ············or·any(context·is·root·or·_contains_exception(root,·context)·for·root·in·errors)
139 ········):135 ········):
140 ············error.__context__·=·None136 ············error.__context__·=·None
141 ········elif·context·is·not·None:137 ········elif·context·is·not·None:
142 ············pending.append(context)138 ············pending.append(context)
143 ········if·error.__cause__·is·not·None:139 ········if·error.__cause__·is·not·None:
144 ············pending.append(error.__cause__)140 ············pending.append(error.__cause__)
145 ········if·isinstance(error,·_exception_group_cls()):141 ········if·_is_exception_group(error):
146 ············pending.extend(cast("_ExceptionGroupProtocol",·error).exceptions)142 ············pending.extend(cast("_ExceptionGroupProtocol",·error).exceptions)
  
Max diff block lines reached; 74153/79688 bytes (93.05%) of diff not shown.
⊟
12.5 KB
filelock/_async.py
    
Offset 4, 18 lines modifiedOffset 4, 26 lines modified
  
4 import·asyncio4 import·asyncio
5 import·contextlib5 import·contextlib
6 import·time6 import·time
7 from·concurrent.futures·import·Future·as·ConcurrentFuture7 from·concurrent.futures·import·Future·as·ConcurrentFuture
8 from·dataclasses·import·dataclass8 from·dataclasses·import·dataclass
9 from·threading·import·Lock9 from·threading·import·Lock
10 from·typing·import·TYPE_CHECKING,·Final,·Generic,·TypeVar,·cast10 from·typing·import·TYPE_CHECKING,·Final,·Generic,·Literal,·NoReturn,·TypeVar,·cast
 11 from·weakref·import·WeakKeyDictionary
  
 12 from·._api·import·_append_exception_context,·_fork_transition,·_raise_chained_errors,·_resolve_read_write_timeout
 13 from·._error·import·Timeout
  
11 if·TYPE_CHECKING:14 if·TYPE_CHECKING:
12 ····from·collections.abc·import·AsyncIterator,·Awaitable,·Callable15 ····from·collections.abc·import·AsyncGenerator,·Awaitable,·Callable
 16 ····from·concurrent.futures·import·Executor
  
 17 ····from·._read_write·import·ReadWriteLock
 18 ····from·._soft_rw·import·SoftReadWriteLock
  
13 _T·=·TypeVar("_T")19 _T·=·TypeVar("_T")
  
  
14 class·_AsyncTransitionUnavailableError(Exception):20 class·_AsyncTransitionUnavailableError(Exception):
15 ····pass21 ····pass
  
Offset 28, 23 lines modifiedOffset 36, 23 lines modified
  
28 class·_AsyncTransitionGate:36 class·_AsyncTransitionGate:
29 ····def·__init__(self)·->·None:37 ····def·__init__(self)·->·None:
30 ········self._tail_lock:·Final[Lock]·=·Lock()38 ········self._tail_lock:·Final[Lock]·=·Lock()
31 ········self._tail:·ConcurrentFuture[None]·|·None·=·None39 ········self._tail:·ConcurrentFuture[None]·|·None·=·None
  
32 ····@contextlib.asynccontextmanager40 ····@contextlib.asynccontextmanager
33 ····async·def·hold(self)·->·AsyncIterator[None]:41 ····async·def·hold(self)·->·AsyncGenerator[None]:
34 ········ticket:·ConcurrentFuture[None]·=·ConcurrentFuture()42 ········ticket:·ConcurrentFuture[None]·=·ConcurrentFuture()
35 ········with·self._tail_lock:43 ········with·self._tail_lock:
36 ············predecessor·=·self._tail44 ············predecessor·=·self._tail
37 ············self._tail·=·ticket45 ············self._tail·=·ticket
38 ········if·predecessor·is·not·None:46 ········if·predecessor·is·not·None:
39 ············try:47 ············try:
40 ················await·_wait_until_done(asyncio.wrap_future(predecessor))48 ················await·_wait_until_done(asyncio.wrap_future(predecessor))
41 ············except·asyncio.CancelledError:49 ············except·BaseException:
42 ················predecessor.add_done_callback(lambda·_predecessor:·self._leave(ticket))50 ················predecessor.add_done_callback(lambda·_predecessor:·self._leave(ticket))
43 ················raise51 ················raise
44 ········try:52 ········try:
45 ············yield53 ············yield
46 ········finally:54 ········finally:
47 ············self._leave(ticket)55 ············self._leave(ticket)
  
Offset 52, 15 lines modifiedOffset 60, 15 lines modified
52 ····async·def·hold_for_acquire(60 ····async·def·hold_for_acquire(
53 ········self,61 ········self,
54 ········*,62 ········*,
55 ········blocking:·bool,63 ········blocking:·bool,
56 ········cancel_check:·Callable[[],·bool]·|·None,64 ········cancel_check:·Callable[[],·bool]·|·None,
57 ········deadline:·float·|·None,65 ········deadline:·float·|·None,
58 ········poll_interval:·float,66 ········poll_interval:·float,
59 ····)·->·AsyncIterator[None]:67 ····)·->·AsyncGenerator[None]:
60 ········ticket:·ConcurrentFuture[None]·=·ConcurrentFuture()68 ········ticket:·ConcurrentFuture[None]·=·ConcurrentFuture()
61 ········with·self._tail_lock:69 ········with·self._tail_lock:
62 ············predecessor·=·self._tail70 ············predecessor·=·self._tail
63 ············self._tail·=·ticket71 ············self._tail·=·ticket
64 ········if·predecessor·is·not·None·and·not·predecessor.done():72 ········if·predecessor·is·not·None·and·not·predecessor.done():
65 ············try:73 ············try:
66 ················await·self._wait_for_predecessor(74 ················await·self._wait_for_predecessor(
Offset 104, 14 lines modifiedOffset 112, 183 lines modified
104 ····def·_leave(self,·ticket:·ConcurrentFuture[None])·->·None:112 ····def·_leave(self,·ticket:·ConcurrentFuture[None])·->·None:
105 ········with·self._tail_lock:113 ········with·self._tail_lock:
106 ············if·self._tail·is·ticket:114 ············if·self._tail·is·ticket:
107 ················self._tail·=·None115 ················self._tail·=·None
108 ········ticket.set_result(None)116 ········ticket.set_result(None)
  
  
 117 class·_TaskOwners:
 118 ····"""
 119 ····Per-task·ownership·in·front·of·a·sync·reader/writer·lock·that·tracks·threads.
  
 120 ····An·async·wrapper·runs·each·call·on·an·executor·thread,·and·that·thread·does·not·identify·the·calling·task.·Waiting
 121 ····writers·block·new·readers·so·a·stream·of·readers·cannot·starve·them.·A·thread·lock·guards·the·table·because·tasks·on
 122 ····different·event·loops·share·it.
 123 ····"""
  
 124 ····def·__init__(self)·->·None:
 125 ········self._lock:·Final[Lock]·=·Lock()
 126 ········self._mode:·Literal["read",·"write"]·|·None·=·None
 127 ········self._depths:·dict[asyncio.Task[object],·int]·=·{}
 128 ········self._transitioning·=·False
 129 ········self._waiting_writers·=·0
 130 ········self._changed:·ConcurrentFuture[None]·=·ConcurrentFuture()
 131 ········#:·The·executor·thread·that·took·the·sync·lock's·level·for·every·task,·which·may·leave·on·another·worker.
 132 ········self.backend_thread:·int·|·None·=·None
  
 133 ····async·def·acquire(
 134 ········self,
 135 ········mode:·Literal["read",·"write"],
 136 ········*,
 137 ········timeout:·float,
 138 ········blocking:·bool,
 139 ········lock_file:·str,
 140 ········enter:·Callable[[float],·Awaitable[None]],
 141 ····)·->·None:
 142 ········task·=·_current_task()
 143 ········timeout·=·_resolve_read_write_timeout(timeout,·blocking=blocking)
 144 ········deadline·=·None·if·not·blocking·or·timeout·<·0·else·time.perf_counter()·+·timeout
 145 ········waiting_writer·=·False
 146 ········try:
 147 ············while·isinstance(
 148 ················admission·:=·self._admit(task,·mode,·lock_file,·waiting_writer=waiting_writer),·ConcurrentFuture
 149 ············):
 150 ················if·not·blocking·or·(deadline·is·not·None·and·time.perf_counter()·>=·deadline):
 151 ····················raise·Timeout(lock_file)
 152 ················if·mode·==·"write"·and·not·waiting_writer:
 153 ····················waiting_writer·=·True
 154 ····················with·self._lock:
 155 ························self._waiting_writers·+=·1
 156 ················wait·=·None·if·deadline·is·None·else·deadline·-·time.perf_counter()
 157 ················await·asyncio.wait((asyncio.wrap_future(admission),),·timeout=wait)
 158 ········finally:
 159 ············if·waiting_writer:
 160 ················with·self._lock:
 161 ····················self._waiting_writers·-=·1
 162 ····················self._notify()
 163 ········if·admission·==·"held":
 164 ············return
 165 ········try:
 166 ············await·enter(-1·if·deadline·is·None·else·max(0.0,·deadline·-·time.perf_counter()))
Max diff block lines reached; 3011/12811 bytes (23.50%) of diff not shown.
⊟
14.8 KB
filelock/_async_read_write.py
    
Offset 2, 50 lines modifiedOffset 2, 58 lines modified
  
2 from·__future__·import·annotations2 from·__future__·import·annotations
  
3 import·asyncio3 import·asyncio
4 import·functools4 import·functools
5 import·os5 import·os
6 import·sqlite36 import·sqlite3
 7 import·threading
7 from·concurrent.futures·import·ThreadPoolExecutor8 from·concurrent.futures·import·ThreadPoolExecutor
8 from·contextlib·import·asynccontextmanager9 from·contextlib·import·asynccontextmanager
9 from·typing·import·TYPE_CHECKING,·ParamSpec,·TypeVar10 from·typing·import·TYPE_CHECKING,·Literal,·ParamSpec,·TypeVar,·cast
  
10 from·._api·import·(11 from·._api·import·(
11 ····_append_exception_context,12 ····_append_exception_context,
12 ····_ensure_current_process,13 ····_ensure_current_process,
13 ····_fork_transition,14 ····_fork_transition,
14 ····_raise_chained_errors, 
15 ····_register_fork_object,15 ····_register_fork_object,
16 )16 )
17 from·._async·import·_BackendOutcome,·_capture_call,·_drain_future,·_future_result,·_wait_until_done17 from·._async·import·(
 18 ····_BackendOutcome,
 19 ····_capture_call,
 20 ····_drain_future,
 21 ····_future_result,
 22 ····_raise_cancelled_error,
 23 ····_task_owners_for,
 24 ····_wait_until_done,
 25 )
18 from·._read_write·import·ReadWriteLock26 from·._read_write·import·ReadWriteLock
  
19 if·TYPE_CHECKING:27 if·TYPE_CHECKING:
20 ····from·collections.abc·import·AsyncGenerator,·Callable28 ····from·collections.abc·import·AsyncGenerator,·Callable
21 ····from·concurrent·import·futures29 ····from·concurrent·import·futures
22 ····from·types·import·TracebackType30 ····from·types·import·TracebackType
23 ····from·typing·import·NoReturn 
  
24 ····from·._api·import·AcquireReturnProxy 
  
25 _P·=·ParamSpec("_P")31 _P·=·ParamSpec("_P")
26 _R·=·TypeVar("_R")32 _R·=·TypeVar("_R")
  
  
27 class·AsyncReadWriteLock:33 class·AsyncReadWriteLock:
28 ····"""34 ····"""
29 ····Async·wrapper·around·:class:`ReadWriteLock`·for·use·in·``asyncio``·applications.35 ····Async·wrapper·around·:class:`ReadWriteLock`·for·use·in·``asyncio``·applications.
  
30 ····This·wrapper·dispatches·every·blocking·SQLite·operation·to·a·thread·pool·via·``loop.run_in_executor()``·because36 ····This·wrapper·dispatches·every·blocking·SQLite·operation·to·a·thread·pool·via·``loop.run_in_executor()``·because
31 ····Python's·:mod:`sqlite3`·module·has·no·async·API.·It·delegates·reentrancy,·upgrade/downgrade·rules,·and·singleton 
32 ····behavior·to·the·underlying·:class:`ReadWriteLock`.37 ····Python's·:mod:`sqlite3`·module·has·no·async·API.·Each·``asyncio``·task·owns·its·own·hold.·Tasks·share·a·read·lock,
 38 ····and·a·task·asking·for·the·write·lock·waits·until·the·other·holders·release,·with·waiting·writers·ahead·of·new
 39 ····readers.·As·with·:class:`ReadWriteLock`,·upgrading·or·downgrading·a·held·lock·raises·:class:`RuntimeError`.
 40 ····Singleton·wrappers·over·one·path·share·their·task·holds.
  
33 ····:param·lock_file:·path·to·the·SQLite·database·file·used·as·the·lock41 ····:param·lock_file:·path·to·the·SQLite·database·file·used·as·the·lock
34 ····:param·timeout:·maximum·wait·time·in·seconds;·``-1``·means·block·indefinitely42 ····:param·timeout:·maximum·wait·time·in·seconds;·``-1``·waits·up·to·SQLite's·busy-timeout·cap·of·about·23·days
35 ····:param·blocking:·if·``False``,·raise·:class:`~filelock.Timeout`·immediately·when·the·lock·is·unavailable43 ····:param·blocking:·if·``False``,·raise·:class:`~filelock.Timeout`·immediately·when·the·lock·is·unavailable
36 ····:param·is_singleton:·if·``True``,·reuse·existing·:class:`ReadWriteLock`·instances·for·the·same·resolved·path44 ····:param·is_singleton:·if·``True``,·reuse·existing·:class:`ReadWriteLock`·instances·for·the·same·resolved·path
37 ····:param·loop:·event·loop·for·``run_in_executor``;·``None``·uses·the·running·loop45 ····:param·loop:·event·loop·for·``run_in_executor``;·``None``·uses·the·running·loop
38 ····:param·executor:·executor·for·``run_in_executor``.·When·``None``·this·lock·creates·and·owns·a·dedicated46 ····:param·executor:·executor·for·``run_in_executor``.·When·``None``·this·lock·creates·and·owns·a·dedicated
39 ········single-thread·executor·so·every·operation·runs·on·the·same·thread·(SQLite·affinity·requires·this)·and·shuts·it47 ········single-thread·executor·so·every·operation·runs·on·the·same·thread·(SQLite·affinity·requires·this)·and·shuts·it
40 ········down·in·:meth:`close`.·This·lock·uses·a·caller-supplied·executor·as-is·and·never·shuts·it·down,·so·after·passing48 ········down·in·:meth:`close`.·This·lock·uses·a·caller-supplied·executor·as-is·and·never·shuts·it·down,·so·after·passing
41 ········no·executor·call·:meth:`close`·to·release·the·owned·one.49 ········no·executor·call·:meth:`close`·to·release·the·owned·one.
Offset 67, 14 lines modifiedOffset 75, 15 lines modified
67 ········creator_pid·=·os.getpid()75 ········creator_pid·=·os.getpid()
68 ········self._creator_pid·=·creator_pid76 ········self._creator_pid·=·creator_pid
69 ········self._fork_invalidated·=·False77 ········self._fork_invalidated·=·False
70 ········self._closed·=·False78 ········self._closed·=·False
71 ········_register_fork_object(self)79 ········_register_fork_object(self)
72 ········with·_fork_transition():80 ········with·_fork_transition():
73 ············self._lock·=·ReadWriteLock(lock_file,·timeout,·blocking=blocking,·is_singleton=is_singleton)81 ············self._lock·=·ReadWriteLock(lock_file,·timeout,·blocking=blocking,·is_singleton=is_singleton)
 82 ············self._owners·=·_task_owners_for(self._lock)
74 ············self._loop·=·loop83 ············self._loop·=·loop
75 ············self._owns_executor·=·executor·is·None84 ············self._owns_executor·=·executor·is·None
76 ············self._executor·=·executor·or·ThreadPoolExecutor(max_workers=1)85 ············self._executor·=·executor·or·ThreadPoolExecutor(max_workers=1)
77 ············if·os.getpid()·!=·creator_pid:··#·pragma:·forked·child86 ············if·os.getpid()·!=·creator_pid:··#·pragma:·forked·child
78 ················msg·=·"AsyncReadWriteLock·construction·cannot·continue·after·fork"87 ················msg·=·"AsyncReadWriteLock·construction·cannot·continue·after·fork"
79 ················raise·RuntimeError(msg)88 ················raise·RuntimeError(msg)
  
Offset 110, 18 lines modifiedOffset 119, 14 lines modified
  
110 ········Falls·back·to·instance·defaults·for·*timeout*·and·*blocking*·when·``None``.119 ········Falls·back·to·instance·defaults·for·*timeout*·and·*blocking*·when·``None``.
  
111 ········:param·timeout:·maximum·wait·time·in·seconds,·or·``None``·to·use·the·instance·default120 ········:param·timeout:·maximum·wait·time·in·seconds,·or·``None``·to·use·the·instance·default
112 ········:param·blocking:·if·``False``,·raise·:class:`~filelock.Timeout`·immediately;·``None``·uses·the·instance·default121 ········:param·blocking:·if·``False``,·raise·:class:`~filelock.Timeout`·immediately;·``None``·uses·the·instance·default
  
113 ········"""122 ········"""
114 ········if·timeout·is·None: 
115 ············timeout·=·self._lock.timeout 
116 ········if·blocking·is·None: 
117 ············blocking·=·self._lock.blocking 
118 ········await·self.acquire_read(timeout,·blocking=blocking)123 ········await·self.acquire_read(timeout,·blocking=blocking)
119 ········body_error:·BaseException·|·None·=·None124 ········body_error:·BaseException·|·None·=·None
120 ········try:125 ········try:
121 ············yield126 ············yield
122 ········except·BaseException·as·error:127 ········except·BaseException·as·error:
123 ············body_error·=·error128 ············body_error·=·error
124 ············raise129 ············raise
Offset 135, 18 lines modifiedOffset 140, 14 lines modified
  
135 ········Falls·back·to·instance·defaults·for·*timeout*·and·*blocking*·when·``None``.140 ········Falls·back·to·instance·defaults·for·*timeout*·and·*blocking*·when·``None``.
  
136 ········:param·timeout:·maximum·wait·time·in·seconds,·or·``None``·to·use·the·instance·default141 ········:param·timeout:·maximum·wait·time·in·seconds,·or·``None``·to·use·the·instance·default
137 ········:param·blocking:·if·``False``,·raise·:class:`~filelock.Timeout`·immediately;·``None``·uses·the·instance·default142 ········:param·blocking:·if·``False``,·raise·:class:`~filelock.Timeout`·immediately;·``None``·uses·the·instance·default
  
138 ········"""143 ········"""
139 ········if·timeout·is·None: 
140 ············timeout·=·self._lock.timeout 
141 ········if·blocking·is·None: 
142 ············blocking·=·self._lock.blocking 
143 ········await·self.acquire_write(timeout,·blocking=blocking)144 ········await·self.acquire_write(timeout,·blocking=blocking)
144 ········body_error:·BaseException·|·None·=·None145 ········body_error:·BaseException·|·None·=·None
145 ········try:146 ········try:
146 ············yield147 ············yield
147 ········except·BaseException·as·error:148 ········except·BaseException·as·error:
148 ············body_error·=·error149 ············body_error·=·error
149 ············raise150 ············raise
Offset 157, 67 lines modifiedOffset 158, 95 lines modified
157 ········try:158 ········try:
158 ············await·self.release()159 ············await·self.release()
159 ········except·BaseException·as·release_error:160 ········except·BaseException·as·release_error:
160 ············if·body_error·is·not·None:161 ············if·body_error·is·not·None:
161 ················_append_exception_context(release_error,·body_error)162 ················_append_exception_context(release_error,·body_error)
162 ············raise163 ············raise
  
163 ····async·def·acquire_read(self,·timeout:·float·=·-1,·*,·blocking:·bool·=·True)·->·AsyncAcquireReadWriteReturnProxy:164 ····async·def·acquire_read(
 165 ········self,·timeout:·float·|·None·=·None,·*,·blocking:·bool·|·None·=·None
 166 ····)·->·AsyncAcquireReadWriteReturnProxy:
Max diff block lines reached; 9442/15115 bytes (62.47%) of diff not shown.
⊟
2.61 KB
filelock/_descriptor.py
    
Offset 1, 16 lines modifiedOffset 1, 18 lines modified
1 """A·minimal·native·lock·over·a·caller-owned·file·descriptor,·contending·with·:class:`FileLock`·on·the·same·file."""1 """A·minimal·native·lock·over·a·caller-owned·file·descriptor,·contending·with·:class:`FileLock`·on·the·same·file."""
  
2 from·__future__·import·annotations2 from·__future__·import·annotations
  
3 import·sys3 import·sys
4 import·time4 import·time
5 from·math·import·isfinite5 from·threading·import·TIMEOUT_MAX
6 from·typing·import·Final6 from·typing·import·Final
  
 7 from·._api·import·_seconds
  
7 if·sys.platform·==·"win32":··#·pragma:·win32·cover8 if·sys.platform·==·"win32":··#·pragma:·win32·cover
8 ····from·._windows·import·_lock_fd_nonblocking,·_unlock_fd9 ····from·._windows·import·_lock_fd_nonblocking,·_unlock_fd
9 else:··#·pragma:·win32·no·cover10 else:··#·pragma:·win32·no·cover
10 ····from·._unix·import·_lock_fd_nonblocking,·_unlock_fd11 ····from·._unix·import·_lock_fd_nonblocking,·_unlock_fd
  
  
11 def·lock_descriptor(fd:·int,·*,·blocking:·bool·=·True,·poll_interval:·float·=·0.05)·->·bool:12 def·lock_descriptor(fd:·int,·*,·blocking:·bool·=·True,·poll_interval:·float·=·0.05)·->·bool:
Offset 24, 30 lines modifiedOffset 26, 31 lines modified
  
24 ····For·timeout,·reentrancy,·singleton,·lifetime,·or·stale-break·behavior,·use·:class:`FileLock`.·There·is·no·async26 ····For·timeout,·reentrancy,·singleton,·lifetime,·or·stale-break·behavior,·use·:class:`FileLock`.·There·is·no·async
25 ····wrapper.·Run·this·in·an·executor,·or·drive·``blocking=False``·from·your·own·polling·loop.27 ····wrapper.·Run·this·in·an·executor,·or·drive·``blocking=False``·from·your·own·polling·loop.
  
26 ····:param·fd:·an·open·file·descriptor·the·caller·owns.28 ····:param·fd:·an·open·file·descriptor·the·caller·owns.
27 ····:param·blocking:·when·``True``·(default),·retry·the·nonblocking·attempt·every·*poll_interval*·seconds·until·it29 ····:param·blocking:·when·``True``·(default),·retry·the·nonblocking·attempt·every·*poll_interval*·seconds·until·it
28 ········succeeds;·when·``False``,·make·one·attempt.30 ········succeeds;·when·``False``,·make·one·attempt.
29 ····:param·poll_interval:·finite,·positive·seconds·between·attempts·while·blocking;·ignored·when·*blocking*·is 
30 ········``False``.31 ····:param·poll_interval:·positive·seconds·between·attempts·while·blocking,·at·most·:data:`threading.TIMEOUT_MAX`;
 32 ········ignored·when·*blocking*·is·``False``.
  
31 ····:returns:·``True``·once·the·lock·is·held,·or·``False``·on·contention·when·``blocking``·is·``False``.33 ····:returns:·``True``·once·the·lock·is·held,·or·``False``·on·contention·when·``blocking``·is·``False``.
  
32 ····:raises·OSError:·for·a·permanent·native·failure,·such·as·an·invalid·descriptor,·or·with·``errno.ENOSYS``·when·the34 ····:raises·OSError:·for·a·permanent·native·failure,·such·as·an·invalid·descriptor,·or·with·``errno.ENOSYS``·when·the
33 ········Python·build·lacks·the·native·locking·primitive.·The·descriptor·is·left·open.35 ········Python·build·lacks·the·native·locking·primitive.·The·descriptor·is·left·open.
34 ····:raises·ValueError:·if·a·blocking·call·receives·a·non-finite·or·non-positive·*poll_interval*.36 ····:raises·ValueError:·if·a·blocking·call·receives·a·*poll_interval*·outside·that·range,·including·``nan``.
  
35 ····..·versionadded::·3.30.037 ····..·versionadded::·3.30.0
  
36 ····"""38 ····"""
37 ····if·not·blocking:39 ····if·not·blocking:
38 ········return·_lock_fd_nonblocking(fd)40 ········return·_lock_fd_nonblocking(fd)
39 ····if·not·isfinite(poll_interval)·or·poll_interval·<=·0:41 ····#·time.sleep·raises·OverflowError·past·TIMEOUT_MAX;·nan·fails·both·comparisons.
 42 ····if·not·0·<·(poll_interval·:=·_seconds("poll_interval",·poll_interval))·<=·TIMEOUT_MAX:
40 ········msg:·Final[str]·=·f"poll_interval·must·be·finite·and·greater·than·0,·got·{poll_interval}"43 ········msg:·Final[str]·=·f"poll_interval·must·be·greater·than·0·and·at·most·{TIMEOUT_MAX},·got·{poll_interval}"
41 ········raise·ValueError(msg)44 ········raise·ValueError(msg)
42 ····while·not·_lock_fd_nonblocking(fd):45 ····while·not·_lock_fd_nonblocking(fd):
43 ········time.sleep(poll_interval)46 ········time.sleep(poll_interval)
44 ····return·True47 ····return·True
  
  
45 def·unlock_descriptor(fd:·int)·->·None:48 def·unlock_descriptor(fd:·int)·->·None:
⊟
3.21 KB
filelock/_error.py
    
Offset 1, 35 lines modifiedOffset 1, 47 lines modified
1 from·__future__·import·annotations1 from·__future__·import·annotations
  
 2 from·typing·import·Final
  
  
2 class·Timeout(TimeoutError):··#·ruff:ignore[error-suffix-on-exception-name]··#·public·exception·name;·renaming·breaks·the·API3 class·Timeout(TimeoutError):··#·ruff:ignore[error-suffix-on-exception-name]··#·public·exception·name;·renaming·breaks·the·API
3 ····"""Raised·when·the·lock·could·not·be·acquired·in·*timeout*·seconds."""4 ····"""Raised·when·the·lock·could·not·be·acquired·in·*timeout*·seconds."""
  
4 ····def·__init__(self,·lock_file:·str)·->·None:5 ····def·__init__(self,·lock_file:·str,·holder:·str·|·None·=·None)·->·None:
5 ········super().__init__()6 ········super().__init__()
6 ········self._lock_file·=·lock_file7 ········self._lock_file·=·lock_file
 8 ········self._holder·=·holder
  
7 ····def·__reduce__(self)·->·tuple[type[Timeout],·tuple[str]]:9 ····def·__reduce__(self)·->·tuple[type[Timeout],·tuple[str],·dict[str,·object]]:
8 ········#·__init__·needs·lock_file,·so·pickle·must·restore·it·as·a·constructor·arg10 ········#·holder·rides·in·the·state·so·a·subclass·taking·only·lock_file,·and·a·4.0.12·reader,·can·still·unpickle·it.
9 ········return·self.__class__,·(self._lock_file,)11 ········return·self.__class__,·(self._lock_file,),·self.__dict__
  
10 ····def·__str__(self)·->·str:··#·pragma:·needs·hard-link12 ····def·__str__(self)·->·str:··#·pragma:·needs·hard-link
11 ········return·f"The·file·lock·'{self._lock_file}'·could·not·be·acquired."13 ········message:·Final·=·f"The·file·lock·'{self._lock_file}'·could·not·be·acquired."
 14 ········if·self._holder·is·None:
 15 ············return·message
 16 ········return·f"{message}·It·is·held·by·{self._holder},·which·this·host·cannot·probe."
  
12 ····def·__repr__(self)·->·str:17 ····def·__repr__(self)·->·str:
13 ········return·f"{self.__class__.__name__}({self.lock_file!r})"18 ········return·f"{self.__class__.__name__}({self.lock_file!r})"
  
14 ····@property19 ····@property
15 ····def·lock_file(self)·->·str:20 ····def·lock_file(self)·->·str:
16 ········"""The·path·of·the·file·lock."""21 ········"""The·path·of·the·file·lock."""
17 ········return·self._lock_file22 ········return·self._lock_file
  
  
18 class·SoftFileLockLifetimeWarning(DeprecationWarning):23 class·SoftFileLockLifetimeWarning(FutureWarning):
 24 ····"""
19 ····"""The·configured·soft-lock·lifetime·permits·overlapping·live·holders·after·expiry."""25 ····The·configured·soft-lock·lifetime·permits·overlapping·live·holders·after·expiry.
  
 26 ····A·:class:`FutureWarning`·shows·by·default·wherever·the·lock·is·configured;·a·:class:`DeprecationWarning`·shows·only
 27 ····in·``__main__``.
  
 28 ····"""
  
  
20 class·LeaseSettingsMismatch(ValueError):··#·ruff:ignore[error-suffix-on-exception-name]··#·public·exception·name;·renaming·breaks·the·API29 class·LeaseSettingsMismatch(ValueError):··#·ruff:ignore[error-suffix-on-exception-name]··#·public·exception·name;·renaming·breaks·the·API
21 ····"""A·lease·contender·disagrees·with·the·published·claim·about·how·long·the·lease·lasts."""30 ····"""A·lease·contender·disagrees·with·the·published·claim·about·how·long·the·lease·lasts."""
  
  
22 class·SoftFileLockProtocolError(OSError):31 class·SoftFileLockProtocolError(OSError):
Offset 39, 16 lines modifiedOffset 51, 18 lines modified
39 ········self._lock_file·=·lock_file51 ········self._lock_file·=·lock_file
40 ········self._claim_name·=·claim_name52 ········self._claim_name·=·claim_name
41 ········self._reason·=·reason53 ········self._reason·=·reason
42 ········super().__init__(self.__str__())54 ········super().__init__(self.__str__())
  
43 ····def·__reduce__(55 ····def·__reduce__(
44 ········self,56 ········self,
45 ····)·->·tuple[type[SoftFileLockProtocolError],·tuple[str,·str·|·None,·str]]:··#·pragma:·needs·hard-link57 ····)·->·tuple[
 58 ········type[SoftFileLockProtocolError],·tuple[str,·str·|·None,·str],·dict[str,·object]
 59 ····]:··#·pragma:·needs·hard-link
46 ········return·self.__class__,·(self._lock_file,·self._claim_name,·self._reason)60 ········return·self.__class__,·(self._lock_file,·self._claim_name,·self._reason),·self.__dict__
  
47 ····def·__str__(self)·->·str:61 ····def·__str__(self)·->·str:
48 ········location·=·self._lock_file·if·self._claim_name·is·None·else·f"{self._lock_file}:·claim·{self._claim_name!r}"62 ········location·=·self._lock_file·if·self._claim_name·is·None·else·f"{self._lock_file}:·claim·{self._claim_name!r}"
49 ········return·f"Invalid·strict·soft-lock·state·at·{location}:·{self._reason}"63 ········return·f"Invalid·strict·soft-lock·state·at·{location}:·{self._reason}"
  
50 ····@property64 ····@property
51 ····def·lock_file(self)·->·str:··#·pragma:·needs·hard-link65 ····def·lock_file(self)·->·str:··#·pragma:·needs·hard-link
⊟
8.59 KB
filelock/_identity.py
    
Offset 1, 40 lines modifiedOffset 1, 99 lines modified
1 from·__future__·import·annotations1 from·__future__·import·annotations
  
 2 import·hashlib
2 import·os3 import·os
3 import·socket4 import·socket
4 import·sys5 import·sys
5 from·errno·import·EPERM,·ESRCH6 from·errno·import·EPERM,·ESRCH
6 from·pathlib·import·Path7 from·pathlib·import·Path
7 from·typing·import·Final8 from·typing·import·Final
  
 9 #:·Every·marker·format·in·this·package·caps·the·hostname·at·the·RFC·1123·limit·and·reads·a·longer·one·as·malformed.
 10 _HOST_NAME_LIMIT:·Final[int]·=·253
 11 #:·The·bytes·those·formats·carry·verbatim:·printable·non-space·ASCII,·less·the·``?``·reserved·for·the·escape.
 12 _HOST_NAME_VERBATIM:·Final[frozenset[int]]·=·frozenset(range(0x21,·0x7F))·-·{ord("?")}
 13 #:·The·characters·at·the·end·of·an·over-long·name·that·carry·a·digest·of·the·part·cut·off.
 14 _HOST_NAME_DIGEST_LEN:·Final[int]·=·8
 15 #:·The·kernel·ABI·fixes·the·initial·PID·namespace's·inode·(``PID_NS_INIT_INO``·in·``linux/nsfs.h``);·every·namespace
 16 #:·created·later·draws·one·from·``0xF0000000``·up,·so·this·value·names·the·host's·own·namespace.
 17 _INITIAL_PID_NAMESPACE:·Final[int]·=·0xEFFFFFFC
 18 _NAMESPACE_MARK:·Final[str]·=·"?pidns-"
  
  
8 def·host_name()·->·str:19 def·host_name()·->·str:
 20 ····"""
9 ····"""The·hostname·recorded·alongside·an·owner,·so·a·marker·written·on·another·machine·is·never·probed·here."""21 ····The·hostname·recorded·alongside·an·owner,·so·a·marker·written·on·another·machine·is·never·probed·here.
10 ····return·socket.gethostname() 
 22 ····Marker·formats·here·hold·the·field·to·printable·non-space·ASCII,·while·``socket.gethostname()``·reports·whatever
 23 ····the·kernel·stores:·a·space,·a·newline·that·forges·an·extra·marker·line,·or·a·byte·no·codec·encodes,·which·Python
 24 ····hands·back·as·a·surrogate.·A·holder·that·publishes·one·raw·writes·a·marker·it·cannot·read·back,·and·loses·the·lock
 25 ····to·the·first·peer·that·ages·it·out·as·malformed.·``?``·is·illegal·in·a·hostname,·so·escaping·it·along·with·every
 26 ····out-of-grammar·byte·as·``?<hex>``·leaves·a·real·name·untouched·and·still·keeps·two·hosts·apart,·which
 27 ····:func:`owner_is_stale`·relies·on·to·refuse·to·probe·a·foreign·PID.
  
 28 ····Linux·appends·the·PID·namespace,·as·Mercurial's·lock·prefix·does.·Two·containers·in·one·pod·share·the·hostname·and
 29 ····the·boot·id·but·not·the·PID·namespace,·so·a·PID·recorded·in·one·names·another·process,·or·none,·in·the·other.·The
 30 ····suffix·starts·with·a·``?``·no·escape·can·produce,·so·``a``·in·a·namespace·never·reads·as·a·host·literally·named
 31 ····``a?pidns-...``.·The·initial·namespace·adds·nothing,·which·keeps·a·host's·name·what·older·releases·recorded.
  
 32 ····An·over-long·name·ends·in·a·digest·of·the·part·cut·to·fit·the·limit.·A·bare·cut·gives·every·name·that·shares·the
 33 ····kept·prefix·one·identity,·and·:func:`owner_is_stale`·would·then·probe·a·local·PID·for·another·host's·holder.
 34 ····"""
 35 ····name·=·(
 36 ········"".join(
 37 ············chr(byte)·if·byte·in·_HOST_NAME_VERBATIM·else·f"?{byte:02x}"
 38 ············for·byte·in·socket.gethostname().encode("utf-8",·"surrogateescape")
 39 ········)
 40 ········+·_pid_namespace_suffix()
 41 ····)
 42 ····if·len(name)·>·_HOST_NAME_LIMIT:
 43 ········keep·=·_HOST_NAME_LIMIT·-·_HOST_NAME_DIGEST_LEN·-·1
 44 ········name·=·f"{name[:keep]}-{hashlib.sha256(name[keep:].encode()).hexdigest()[:_HOST_NAME_DIGEST_LEN]}"
 45 ····#·An·escape·is·three·characters·and·a·kept·byte·is·never·'?',·so·a·bare·'?'·can·only·mean·an·empty·hostname.
 46 ····return·name·or·"?"
  
  
 47 def·_pid_namespace_suffix()·->·str:
 48 ····try:
 49 ········namespace:·Final·=·Path("/proc/self/ns/pid").stat().st_ino
 50 ····except·OSError:··#·only·Linux·3.8+·has·the·file,·and·a·sandbox·may·hide·it;·nothing·else·tells·namespaces·apart
 51 ········return·""
 52 ····return·""·if·namespace·==·_INITIAL_PID_NAMESPACE·else·f"{_NAMESPACE_MARK}{namespace:x}"
  
  
11 def·owner_is_stale(pid:·int,·hostname:·str,·start_token:·int·|·None)·->·bool:53 def·owner_is_stale(pid:·int,·hostname:·str,·start_token:·int·|·None)·->·bool:
12 ····"""54 ····"""
13 ····Whether·the·recorded·owner·is·provably·gone,·so·reclaiming·its·marker·cannot·detach·a·live·holder.55 ····Whether·the·recorded·owner·is·provably·gone,·so·reclaiming·its·marker·cannot·detach·a·live·holder.
  
14 ····Fail·closed:·return·``True``·only·when·this·process·can·prove·the·exact·recorded·owner·is·dead.·A·marker·from56 ····Fail·closed:·return·``True``·only·when·this·process·can·prove·the·exact·recorded·owner·is·dead.·A·marker·from
15 ····another·host·cannot·be·probed;·a·live·PID·whose·start·token·still·matches,·or·whose·token·cannot·be·read,·is·the57 ····another·host·cannot·be·probed;·a·live·PID·whose·start·token·still·matches,·or·whose·token·cannot·be·read,·is·the
16 ····holder·or·is·indistinguishable·from·it;·a·live·PID·whose·start·token·differs·is·a·recycled·PID,·so·the·process·that58 ····holder·or·is·indistinguishable·from·it;·a·live·PID·whose·start·token·differs·is·a·recycled·PID,·so·the·process·that
17 ····wrote·the·marker·is·gone.·PostgreSQL,·Qt·``QLockFile``·and·Mercurial·all·break·a·stale·lock·only·on·proof·of·death59 ····wrote·the·marker·is·gone.·PostgreSQL,·Qt·``QLockFile``·and·Mercurial·all·break·a·stale·lock·only·on·proof·of·death
18 ····and·treat·an·unreadable·or·foreign·owner·as·still·holding.60 ····and·treat·an·unreadable·or·foreign·owner·as·still·holding.
19 ····"""61 ····"""
20 ····if·hostname·!=·host_name():62 ····if·hostname·!=·host_name():
21 ········return·False63 ········return·False
22 ····if·not·process_alive(pid):64 ····if·process_alive(pid)·and·(start_token·is·None·or·process_start_token(pid)·in·{None,·start_token}):
23 ········return·True65 ········return·False
24 ····if·start_token·is·None:66 ····#·Only·a·bare·hostname·can·be·an·older·release's,·written·from·a·container·that·shares·this·host's·name.
 67 ····return·_NAMESPACE_MARK·in·hostname·or·not·_owner_runs_elsewhere(pid,·start_token)
  
  
 68 def·owner_is_current_process(pid:·int,·hostname:·str,·start_token:·int·|·None)·->·bool:
 69 ····"""
 70 ····Whether·the·recorded·owner·is·this·process,·so·a·marker·a·recycled·PID·left·behind·never·reads·as·ours.
  
 71 ····Fail·closed:·a·recorded·start·token·must·match·this·process's.·One·that·differs·was·written·by·an·earlier·process
 72 ····that·reused·this·PID,·and·when·this·process·cannot·read·its·own·token·nothing·proves·the·marker·is·ours.·A·marker
 73 ····without·a·token·falls·back·to·the·PID·and·hostname.
 74 ····"""
 75 ····if·pid·!=·os.getpid()·or·hostname·!=·host_name():
25 ········return·False76 ········return·False
 77 ····return·start_token·is·None·or·start_token·==·process_start_token(pid)
26 ····current·=·process_start_token(pid) 
27 ····return·current·is·not·None·and·current·!=·start_token 
  
  
28 if·sys.platform·==·"win32":··#·pragma:·win32·cover78 if·sys.platform·==·"win32":··#·pragma:·win32·cover
29 ····import·ctypes79 ····import·ctypes
30 ····from·ctypes·import·wintypes80 ····from·ctypes·import·wintypes
  
31 ····_KERNEL32:·Final[ctypes.WinDLL]·=·ctypes.WinDLL("kernel32",·use_last_error=True)81 ····_KERNEL32:·Final[ctypes.WinDLL]·=·ctypes.WinDLL("kernel32",·use_last_error=True)
Offset 130, 14 lines modifiedOffset 189, 47 lines modified
130 ················return·None189 ················return·None
131 ············try:190 ············try:
132 ················starttime·=·int(fields[_STARTTIME_INDEX])191 ················starttime·=·int(fields[_STARTTIME_INDEX])
133 ············except·ValueError:··#·pragma:·no·cover··#·/proc·always·renders·starttime·as·an·integer192 ············except·ValueError:··#·pragma:·no·cover··#·/proc·always·renders·starttime·as·an·integer
134 ················return·None193 ················return·None
135 ············return·(_BOOT_ID·<<·64)·|·starttime194 ············return·(_BOOT_ID·<<·64)·|·starttime
  
 195 ········def·_owner_runs_elsewhere(pid:·int,·start_token:·int·|·None)·->·bool:
 196 ············"""
 197 ············Whether·the·owner·runs·in·another·PID·namespace·as·*pid*.
  
 198 ············An·older·release·in·a·container·sharing·this·hostname·recorded·its·in-container·PID,·which·means·nothing
 199 ············here.·starttime·and·the·boot·id·are·kernel-wide,·so·a·task·with·that·start·token·whose·innermost·PID·is
 200 ············*pid*·is·the·owner;·one·that·merely·started·in·the·same·tick·is·not.
 201 ············"""
 202 ············if·start_token·is·None·or·start_token·>>·64·!=·_BOOT_ID:
 203 ················return·False
 204 ············try:
 205 ················with·os.scandir("/proc")·as·entries:
 206 ····················return·any(
 207 ························entry.name.isdigit()
 208 ························and·(task·:=·int(entry.name))·!=·pid
 209 ························and·process_start_token(task)·==·start_token
 210 ························and·_innermost_pid(task)·==·pid
 211 ························for·entry·in·entries
Max diff block lines reached; 925/8755 bytes (10.57%) of diff not shown.
⊟
21.9 KB
filelock/_lease.py
    
Offset 1, 37 lines modifiedOffset 1, 39 lines modified
1 from·__future__·import·annotations1 from·__future__·import·annotations
  
2 import·os2 import·os
3 import·secrets3 import·secrets
 4 import·sys
4 import·time5 import·time
5 from·contextlib·import·suppress6 from·contextlib·import·suppress
6 from·dataclasses·import·dataclass7 from·dataclasses·import·dataclass
 8 from·math·import·isfinite
7 from·threading·import·Event,·Thread,·current_thread,·local9 from·threading·import·Event,·Thread,·current_thread
8 from·typing·import·TYPE_CHECKING,·Literal10 from·typing·import·TYPE_CHECKING,·Final,·Literal,·cast
 11 from·weakref·import·WeakMethod
  
 12 from·._api·import·_check_timeout_max,·_seconds
9 from·._error·import·LeaseSettingsMismatch13 from·._error·import·LeaseSettingsMismatch
10 from·._identity·import·owner_is_stale14 from·._identity·import·owner_is_stale
11 from·._marker·import·MarkerSoftFileLock,·OwnerMode,·OwnerRecord,·parse_marker15 from·._marker·import·MarkerSoftFileLock,·OwnerMode,·OwnerRecord,·parse_marker
12 from·._soft·import·_read_lock_file16 from·._soft·import·_read_lock_file
13 from·._util·import·break_lock_file,·touch17 from·._util·import·break_lock_file,·touch
  
14 if·TYPE_CHECKING:18 if·TYPE_CHECKING:
15 ····import·sys 
16 ····from·collections.abc·import·Callable19 ····from·collections.abc·import·Callable,·Mapping
 20 ····from·typing·import·Unpack
  
17 ····from·._api·import·LockOptions21 ····from·._api·import·LockOptions,·_ExtraValue
  
 22 #:·``evicted``·is·a·:class:`~filelock.SoftReadWriteLock`·loss:·a·peer·waited·out·the·stale·threshold·and·committed·a
 23 #:·generation·without·this·holder.
 24 CompromiseReason·=·Literal["marker-missing",·"owner-changed",·"refresh-failed",·"evicted"]
18 ····if·sys.version_info·>=·(3,·11):··#·pragma:·no·cover·(py311+) 
19 ········from·typing·import·Unpack 
20 ····else:··#·pragma:·no·cover·(<py311) 
21 ········from·typing_extensions·import·Unpack 
  
 25 _RefreshOutcome·=·Literal["ok",·"transient",·"marker-missing",·"owner-changed"]
 26 _DEFAULT_LEASE_DURATION:·Final[float]·=·30.0
22 CompromiseReason·=·Literal["marker-missing",·"owner-changed",·"refresh-failed"] 
  
23 _RefreshOutcome·=·Literal["ok",·"lost",·"transient"] 
  
  
24 @dataclass(frozen=True)27 @dataclass(frozen=True)
25 class·LeaseCompromise:28 class·LeaseCompromise:
26 ····"""Why·a·held·lease·stopped·being·this·process's·to·hold."""29 ····"""Why·a·held·lease·stopped·being·this·process's·to·hold."""
  
27 ····lock_file:·str30 ····lock_file:·str
Offset 53, 36 lines modifiedOffset 55, 23 lines modified
53 ····"""The·state·of·one·claim:·its·token,·its·heartbeat,·and·how·that·claim·was·lost."""55 ····"""The·state·of·one·claim:·its·token,·its·heartbeat,·and·how·that·claim·was·lost."""
  
54 ····token:·str·|·None·=·None56 ····token:·str·|·None·=·None
55 ····compromise:·LeaseCompromise·|·None·=·None57 ····compromise:·LeaseCompromise·|·None·=·None
56 ····heartbeat:·_Heartbeat·|·None·=·None58 ····heartbeat:·_Heartbeat·|·None·=·None
  
  
57 class·_LeaseClaimHolder: 
58 ····"""Holds·the·claim·its·owning·context·acquired.""" 
  
59 ····#·Only·the·holder·is·thread-local,·mirroring·FileLockContext:·the·claim·stays·an·ordinary·object,·so·the·heartbeat 
60 ····#·thread·records·a·compromise·where·the·thread·that·acquired·the·lease·reads·it. 
  
61 ····def·__init__(self)·->·None: 
62 ········self.claim·=·_LeaseClaim() 
  
  
63 class·_ThreadLocalLeaseClaimHolder(_LeaseClaimHolder,·local): 
64 ····"""A·thread·local·version·of·the·``_LeaseClaimHolder``·class.""" 
  
  
65 class·SoftFileLease(MarkerSoftFileLock):59 class·SoftFileLease(MarkerSoftFileLock):
66 ····"""60 ····"""
67 ····Existence·lock·whose·claim·expires,·so·a·peer·may·take·it·while·the·previous·holder·still·runs.61 ····Existence·lock·whose·claim·expires,·so·a·peer·may·take·it·while·the·previous·holder·still·runs.
  
68 ····A·lease·trades·mutual·exclusion·for·progress.·The·holder·publishes·a·claim·and·refreshes·it·every62 ····A·lease·trades·mutual·exclusion·for·progress.·The·holder·publishes·a·claim·and·refreshes·it·every
69 ····``heartbeat_interval``·seconds;·a·contender·takes·the·marker·once·it·is·``lease_duration``·seconds·stale.·Nothing63 ····``heartbeat_interval``·seconds;·a·contender·takes·the·marker·once·it·has·seen·no·refresh·for·``lease_duration``
 64 ····seconds·of·its·own·monotonic·clock,·so·clock·skew·between·hosts·cannot·expire·a·live·claim.·Nothing·stops·the
70 ····stops·the·expired·holder:·it·keeps·running,·and·it·keeps·using·whatever·the·lock·protects.·Treat·the·lease·as·a·hint65 ····expired·holder:·it·keeps·running,·and·it·keeps·using·whatever·the·lock·protects.·Treat·the·lease·as·a·hint·about
71 ····about·who·*should*·be·working,·not·as·a·guarantee·that·only·one·worker·is.66 ····who·*should*·be·working,·not·as·a·guarantee·that·only·one·worker·is.
  
72 ····To·make·a·protected·resource·reject·a·superseded·holder,·that·resource·must·be·linearizable·and·must·fence·on·a67 ····To·make·a·protected·resource·reject·a·superseded·holder,·that·resource·must·be·linearizable·and·must·fence·on·a
73 ····monotonic·generation·it·controls.·:attr:`token`·names·a·claim;·it·does·not·fence·one.·Where·overlap·is·unacceptable,68 ····monotonic·generation·it·controls.·:attr:`token`·names·a·claim;·it·does·not·fence·one.·Where·overlap·is·unacceptable,
74 ····use·:class:`StrictSoftFileLock·<filelock.StrictSoftFileLock>`·instead.69 ····use·:class:`StrictSoftFileLock·<filelock.StrictSoftFileLock>`·instead.
  
75 ····Every·contender·for·a·path·must·agree·on·``lease_duration``.·A·contender·that·finds·a·claim·published·under·a70 ····Every·contender·for·a·path·must·agree·on·``lease_duration``.·A·contender·that·finds·a·claim·published·under·a
76 ····different·duration·raises·:class:`LeaseSettingsMismatch·<filelock.LeaseSettingsMismatch>`·rather·than·apply·its·own71 ····different·duration·raises·:class:`LeaseSettingsMismatch·<filelock.LeaseSettingsMismatch>`·rather·than·apply·its·own
Offset 108, 54 lines modifiedOffset 97, 80 lines modified
108 ····_lifetime_supported:·bool·=·False97 ····_lifetime_supported:·bool·=·False
109 ····_lifetime_unsupported_reason:·str·=·"lease_duration·sets·when·a·lease·expires"98 ····_lifetime_unsupported_reason:·str·=·"lease_duration·sets·when·a·lease·expires"
  
110 ····def·__init__(99 ····def·__init__(
111 ········self,100 ········self,
112 ········lock_file:·str·|·os.PathLike[str],101 ········lock_file:·str·|·os.PathLike[str],
113 ········*,102 ········*,
114 ········lease_duration:·float·=·30.0,103 ········lease_duration:·float·=·_DEFAULT_LEASE_DURATION,
115 ········heartbeat_interval:·float·|·None·=·None,104 ········heartbeat_interval:·float·|·None·=·None,
116 ········on_compromise:·Callable[[LeaseCompromise],·None]·|·None·=·None,105 ········on_compromise:·Callable[[LeaseCompromise],·None]·|·None·=·None,
117 ········**kwargs:·Unpack[LockOptions],106 ········**kwargs:·Unpack[LockOptions],
118 ····)·->·None:107 ····)·->·None:
119 ········"""108 ········"""
120 ········Create·a·lease.109 ········Create·a·lease.
  
121 ········:param·lease_duration:·seconds·of·marker·staleness·after·which·a·contender·may·take·the·claim.·Every·contender110 ········:param·lease_duration:·seconds·a·contender·must·see·the·marker·go·unrefreshed·before·it·may·take·the·claim.
122 ············for·the·path·must·pass·the·same·value.111 ············Every·contender·for·the·path·must·pass·the·same·value.
123 ········:param·heartbeat_interval:·seconds·between·refreshes.·Defaults·to·a·third·of·``lease_duration``,·leaving·room112 ········:param·heartbeat_interval:·seconds·between·refreshes.·Defaults·to·a·third·of·``lease_duration``,·leaving·room
124 ············for·two·missed·refreshes·before·a·peer·may·take·the·claim.·Must·be·shorter·than·``lease_duration``.113 ············for·two·missed·refreshes·before·a·peer·may·take·the·claim.·Must·be·shorter·than·``lease_duration``·and·at
 114 ············most·:data:`threading.TIMEOUT_MAX`.
125 ········:param·on_compromise:·called·from·the·heartbeat·thread·with·a·:class:`LeaseCompromise`·when·the·claim·is·lost.115 ········:param·on_compromise:·called·from·the·heartbeat·thread·with·a·:class:`LeaseCompromise`·when·the·claim·is·lost.
126 ········:param·kwargs:·every·other·:class:`BaseFileLock·<filelock.BaseFileLock>`·option,·``timeout``·and·``mode``·among116 ········:param·kwargs:·every·other·:class:`BaseFileLock·<filelock.BaseFileLock>`·option,·``timeout``·and·``mode``·among
127 ············them.·The·metaclass·passes·them·all·by·keyword,·and·taking·them·here·lets117 ············them.·The·metaclass·passes·them·all·by·keyword,·and·taking·them·here·lets
128 ············:class:`AsyncSoftFileLease·<filelock.AsyncSoftFileLease>`·add·the·async·plumbing·a·fixed·signature·would118 ············:class:`AsyncSoftFileLease·<filelock.AsyncSoftFileLease>`·add·the·async·plumbing·a·fixed·signature·would
129 ············hide.119 ············hide.
  
130 ········"""120 ········"""
131 ········if·lease_duration·<=·0:121 ········#·A·plain·float:·the·marker·records·its·repr,·which·NumPy's·float64·spells·in·a·form·no·parser·reads.
 122 ········if·not·isfinite(lease_duration·:=·_seconds("lease_duration",·lease_duration))·or·lease_duration·<=·0:
132 ············msg·=·f"lease_duration·must·be·positive,·got·{lease_duration!r}"123 ············msg·=·f"lease_duration·must·be·positive·and·finite,·got·{lease_duration!r}"
133 ············raise·ValueError(msg)124 ············raise·ValueError(msg)
134 ········if·heartbeat_interval·is·None:125 ········heartbeat_interval·=·(
135 ············heartbeat_interval·=·lease_duration·/·3126 ············lease_duration·/·3·if·heartbeat_interval·is·None·else·_seconds("heartbeat_interval",·heartbeat_interval)
 127 ········)
136 ········if·not·0·<·heartbeat_interval·<·lease_duration:128 ········if·not·0·<·heartbeat_interval·<·lease_duration:
137 ············msg·=·f"heartbeat_interval·must·be·positive·and·below·lease_duration,·got·{heartbeat_interval!r}"129 ············msg·=·f"heartbeat_interval·must·be·positive·and·below·lease_duration,·got·{heartbeat_interval!r}"
138 ············raise·ValueError(msg)130 ············raise·ValueError(msg)
 131 ········_check_timeout_max("heartbeat_interval",·heartbeat_interval)
139 ········super().__init__(lock_file,·**kwargs)132 ········super().__init__(lock_file,·**kwargs)
140 ········self._lease_duration·=·lease_duration133 ········self._lease_duration·=·lease_duration
141 ········self._heartbeat_interval·=·heartbeat_interval134 ········self._heartbeat_interval·=·heartbeat_interval
Max diff block lines reached; 15268/22353 bytes (68.30%) of diff not shown.
⊟
8.45 KB
filelock/_marker.py
    
Offset 1, 46 lines modifiedOffset 1, 39 lines modified
1 from·__future__·import·annotations1 from·__future__·import·annotations
  
2 import·math2 import·math
3 import·os3 import·os
 4 import·re
4 from·contextlib·import·suppress5 from·contextlib·import·suppress
5 from·typing·import·Final,·Literal,·NamedTuple6 from·typing·import·Final,·Literal,·NamedTuple
  
6 from·._identity·import·host_name,·process_start_token7 from·._identity·import·host_name,·owner_is_current_process,·owner_is_stale,·process_start_token
7 from·._soft·import·SoftFileLock,·_read_lock_file8 from·._soft·import·SoftFileLock,·_read_lock_file,·parse_decimal
8 from·._util·import·write_all9 from·._util·import·break_lock_file,·write_all
  
9 #:·Protocol·1·is·the·legacy·``<pid>\n<hostname>\n[<start_token>\n]``·marker·that·:class:`SoftFileLock`·still·writes.10 #:·Protocol·1·is·the·legacy·``<pid>\n<hostname>\n[<start_token>\n]``·marker·that·:class:`SoftFileLock`·still·writes.
10 #:·Protocol·2·carries·the·owner·mode·and·the·lease·claim.·A·protocol·1·reader·treats·a·protocol·2·marker·as·malformed11 #:·Protocol·2·carries·the·owner·mode·and·the·lease·claim.·A·protocol·1·reader·treats·a·protocol·2·marker·as·malformed
11 #:·and·evicts·it·after·its·grace·period,·so·the·two·never·guarantee·mutual·exclusion·against·each·other.12 #:·and·evicts·it·after·its·grace·period,·so·the·two·never·guarantee·mutual·exclusion·against·each·other.
12 _PROTOCOL:·Final[str]·=·"filelock/2"13 _PROTOCOL:·Final[str]·=·"filelock/2"
  
13 _MAX_PID:·Final[int]·=·2**31·-·114 _MAX_PID:·Final[int]·=·2**31·-·1
  
14 #:·``unknown``·is·never·published:·it·names·a·mode·some·other·filelock·wrote·that·this·version·cannot·interpret.·Such·a 
15 #:·record·still·identifies·a·live·owner,·so·it·is·parsed·rather·than·read·as·malformed·and·aged·out. 
16 OwnerMode·=·Literal["lease",·"unknown"]15 #:·The·forms·``repr``·gives·a·non-negative·finite·float·or·int;·``float()``·would·also·accept·whitespace,·underscores
 16 #:·and·non-ASCII·digits.
 17 _DURATION:·Final[re.Pattern[str]]·=·re.compile(r"[0-9]+(?:\.[0-9]+)?(?:e[+-][0-9]+)?",·re.ASCII)
  
 18 #:·Preserve·unknown·contracts·so·contenders·cannot·mistake·them·for·malformed,·reclaimable·markers.
 19 OwnerMode·=·Literal["lease",·"exclusive",·"unknown"]
  
17 class·OwnerRecord(NamedTuple): 
18 ····"""The·owner·published·in·a·protocol·2·marker.""" 
  
19 ····pid:·int 
20 ····hostname:·str 
21 ····mode:·OwnerMode 
22 ····token:·str·|·None·=·None 
23 ····lease_duration:·float·|·None·=·None 
24 ····start:·int·|·None·=·None 
  
  
25 class·MarkerSoftFileLock(SoftFileLock):20 class·MarkerSoftFileLock(SoftFileLock):
26 ····"""An·existence·lock·whose·marker·carries·a·protocol·2·owner·record."""21 ····"""An·existence·lock·whose·marker·carries·a·protocol·2·owner·record."""
  
27 ····#:·Filled·in·by·each·mode·so·the·published·record·states·the·contract·its·holder·acquired·under.22 ····#:·Age-based·expiry·requires·a·lease·contract;·an·exclusive·holder·grants·none.
28 ····_owner_mode:·OwnerMode23 ····_owner_mode:·OwnerMode·=·"exclusive"
  
29 ····@property24 ····@property
30 ····def·owner(self)·->·OwnerRecord·|·None:25 ····def·owner(self)·->·OwnerRecord·|·None:
31 ········"""26 ········"""
32 ········The·owner·named·by·the·marker·on·disk.27 ········The·owner·named·by·the·marker·on·disk.
  
33 ········:returns:·the·published·record,·or·``None``·when·no·marker·exists·or·its·record·is·malformed·or·protocol·128 ········:returns:·the·published·record,·or·``None``·when·no·marker·exists·or·its·record·is·malformed·or·protocol·1
Offset 59, 29 lines modifiedOffset 52, 44 lines modified
59 ········return·None·if·(owner·:=·self._read_owner())·is·None·else·owner.pid52 ········return·None·if·(owner·:=·self._read_owner())·is·None·else·owner.pid
  
60 ····@property53 ····@property
61 ····def·is_lock_held_by_us(self)·->·bool:54 ····def·is_lock_held_by_us(self)·->·bool:
62 ········"""55 ········"""
63 ········Whether·the·marker·on·disk·names·this·process.56 ········Whether·the·marker·on·disk·names·this·process.
  
64 ········:returns:·``True``·when·the·marker's·PID·and·hostname·match·this·process57 ········:returns:·``True``·when·the·marker·names·this·process's·PID,·hostname·and,·when·recorded,·start·token
  
65 ········"""58 ········"""
66 ········owner·=·self._read_owner()59 ········owner·=·self._read_owner()
67 ········return·owner·is·not·None·and·owner.pid·==·os.getpid()·and·owner.hostname·==·host_name()60 ········return·owner·is·not·None·and·owner_is_current_process(owner.pid,·owner.hostname,·owner.start)
  
68 ····def·force_break(self)·->·None:61 ····def·force_break(self)·->·None:
69 ········"""62 ········"""
70 ········Remove·the·marker·whoever·holds·it,·so·a·later·contender·can·acquire.63 ········Remove·the·marker·whoever·holds·it,·so·a·later·contender·can·acquire.
  
71 ········Forced·breaking·voids·mutual·exclusion:·the·previous·holder·keeps·running·and·keeps·using·whatever·the·lock64 ········Forced·breaking·voids·mutual·exclusion:·the·previous·holder·keeps·running·and·keeps·using·whatever·the·lock
72 ········protects.·Reserve·it·for·an·operator·clearing·a·marker·whose·holder·is·known·to·be·gone.65 ········protects.·Reserve·it·for·an·operator·clearing·a·marker·whose·holder·is·known·to·be·gone.
73 ········"""66 ········"""
74 ········self.break_lock()67 ········self.break_lock()
  
 68 ····def·_try_break_stale_lock(self)·->·None:
 69 ········with·suppress(OSError,·ValueError):
 70 ············snapshot:·Final[tuple[str·|·None,·float,·int]]·=·_read_lock_file(self.lock_file)
 71 ············owner:·Final[OwnerRecord·|·None]
 72 ············if·(owner·:=·parse_marker(snapshot[0]))·is·None:
 73 ················super()._try_break_stale_lock()
 74 ············elif·owner.mode·!=·"unknown"·and·owner_is_stale(owner.pid,·owner.hostname,·owner.start):
 75 ················break_lock_file(self.lock_file,·*snapshot[1:])
  
 76 ····@classmethod
 77 ····def·_recorded_holder(cls,·content:·str·|·None)·->·tuple[int,·str]·|·None:
 78 ········if·(owner·:=·parse_marker(content))·is·not·None:
 79 ············return·owner.pid,·owner.hostname
 80 ········return·super()._recorded_holder(content)
  
75 ····def·_read_owner(self)·->·OwnerRecord·|·None:81 ····def·_read_owner(self)·->·OwnerRecord·|·None:
76 ········with·suppress(OSError,·ValueError):82 ········with·suppress(OSError,·ValueError):
77 ············return·parse_marker(_read_lock_file(self.lock_file)[0])83 ············return·parse_marker(_read_lock_file(self.lock_file)[0])
78 ········return·None84 ········return·None
  
79 ····def·_write_lock_info(self,·fd:·int)·->·None:85 ····def·_write_lock_info(self,·fd:·int)·->·None:
80 ········write_all(fd,·encode_marker(self._published_record()))86 ········write_all(fd,·encode_marker(self._published_record()))
Offset 91, 29 lines modifiedOffset 99, 41 lines modified
91 ············pid=os.getpid(),99 ············pid=os.getpid(),
92 ············hostname=host_name(),100 ············hostname=host_name(),
93 ············mode=self._owner_mode,101 ············mode=self._owner_mode,
94 ············start=process_start_token(os.getpid()),102 ············start=process_start_token(os.getpid()),
95 ········)103 ········)
  
  
 104 class·OwnerRecord(NamedTuple):
 105 ····"""Keep·optional·metadata·when·reading·unknown·lock·modes."""
  
 106 ····pid:·int
 107 ····hostname:·str
 108 ····mode:·OwnerMode
 109 ····token:·str·|·None·=·None
 110 ····lease_duration:·float·|·None·=·None
 111 ····start:·int·|·None·=·None
  
  
96 def·encode_marker(record:·OwnerRecord)·->·bytes:112 def·encode_marker(record:·OwnerRecord)·->·bytes:
97 ····"""Render·an·owner·record·as·the·bytes·a·protocol·2·marker·holds."""113 ····"""Render·an·owner·record·as·the·bytes·a·protocol·2·marker·holds."""
98 ····lines·=·[_PROTOCOL,·f"pid={record.pid}",·f"host={record.hostname}",·f"mode={record.mode}"]114 ····lines·=·[_PROTOCOL,·f"pid={record.pid}",·f"host={record.hostname}",·f"mode={record.mode}"]
99 ····if·record.token·is·not·None:115 ····if·record.token·is·not·None:
100 ········lines.append(f"token={record.token}")116 ········lines.append(f"token={record.token}")
101 ····if·record.lease_duration·is·not·None:117 ····if·record.lease_duration·is·not·None:
102 ········lines.append(f"duration={record.lease_duration!r}")118 ········lines.append(f"duration={record.lease_duration!r}")
103 ····if·record.start·is·not·None:119 ····if·record.start·is·not·None:
104 ········lines.append(f"start={record.start}")120 ········lines.append(f"start={record.start}")
105 ····return·"".join(f"{line}\n"·for·line·in·lines).encode()121 ····return·"".join(f"{line}\n"·for·line·in·lines).encode()
  
  
Max diff block lines reached; 2959/8614 bytes (34.35%) of diff not shown.
⊟
43.2 KB
filelock/_read_write.py
    
Offset 1, 37 lines modifiedOffset 1, 52 lines modified
1 from·__future__·import·annotations1 from·__future__·import·annotations
  
 2 import·hashlib
2 import·logging3 import·logging
3 import·os4 import·os
4 import·pathlib5 import·pathlib
 6 import·shutil
5 import·sqlite37 import·sqlite3
 8 import·stat
6 import·sys9 import·sys
 10 import·tempfile
7 import·threading11 import·threading
8 import·time12 import·time
 13 from·collections·import·deque
9 from·contextlib·import·contextmanager,·suppress14 from·contextlib·import·contextmanager,·suppress
 15 from·dataclasses·import·dataclass,·field
 16 from·itertools·import·count
10 from·typing·import·TYPE_CHECKING,·ClassVar,·Final,·Literal,·TypeAlias,·cast17 from·typing·import·TYPE_CHECKING,·ClassVar,·Final,·Literal,·NamedTuple,·TypeAlias,·cast
11 from·weakref·import·WeakValueDictionary18 from·weakref·import·WeakValueDictionary
  
12 from·._api·import·(19 from·._api·import·(
13 ····AcquireReturnProxy,20 ····AcquireReturnProxy,
 21 ····_canonical,
14 ····_ensure_current_process,22 ····_ensure_current_process,
15 ····_fork_transition,23 ····_fork_transition,
16 ····_raise_chained_errors,24 ····_raise_chained_errors,
17 ····_register_fork_class,25 ····_register_fork_class,
18 ····_register_fork_object,26 ····_register_fork_object,
 27 ····_register_owned_descriptor,
 28 ····_resolve_read_write_timeout,
 29 ····_seconds,
 30 ····_timeout_behavior,
 31 ····_unregister_owned_descriptor,
19 )32 )
20 from·._error·import·Timeout33 from·._error·import·Timeout
 34 from·._identity·import·host_name,·owner_is_stale,·process_start_token
  
 35 if·sys.platform·==·"win32":··#·pragma:·win32·cover
 36 ····from·._windows·import·_open_non_reparse_fd
  
21 if·TYPE_CHECKING:37 if·TYPE_CHECKING:
22 ····from·collections.abc·import·Callable,·Generator38 ····from·collections.abc·import·Callable,·Generator
 39 ····from·typing·import·Self
  
 40 ····from·_typeshed·import·Unused
23 ····if·sys.version_info·>=·(3,·11): 
24 ········from·typing·import·Self 
25 ····else: 
26 ········from·typing_extensions·import·Self 
  
27 _LOGGER:·Final[logging.Logger]·=·logging.getLogger("filelock")41 _LOGGER:·Final[logging.Logger]·=·logging.getLogger("filelock")
28 _GETPID:·Final[Callable[[],·int]]·=·os.getpid42 _GETPID:·Final[Callable[[],·int]]·=·os.getpid
29 _IS_PYPY:·Final[bool]·=·sys.implementation.name·==·"pypy"43 _IS_PYPY:·Final[bool]·=·sys.implementation.name·==·"pypy"
30 _NEEDS_CONNECTION_ESCROW:·Final[bool]·=·(44 _NEEDS_CONNECTION_ESCROW:·Final[bool]·=·(
31 ····hasattr(os,·"register_at_fork")·and·sys.implementation.name·==·"cpython"·and·sys.version_info·<·(3,·12)45 ····hasattr(os,·"register_at_fork")·and·sys.implementation.name·==·"cpython"·and·sys.version_info·<·(3,·12)
32 )46 )
Offset 39, 14 lines modifiedOffset 54, 23 lines modified
39 ····str·|·bytes·|·os.PathLike[str]·|·os.PathLike[bytes]·|·float·|·int·|·type[sqlite3.Connection]·|·None54 ····str·|·bytes·|·os.PathLike[str]·|·os.PathLike[bytes]·|·float·|·int·|·type[sqlite3.Connection]·|·None
40 )55 )
41 _DatabaseIdentity:·TypeAlias·=·tuple[int,·int]56 _DatabaseIdentity:·TypeAlias·=·tuple[int,·int]
  
42 #·sqlite3_busy_timeout()·accepts·a·C·int,·max·2_147_483_647·on·32-bit.·Use·a·lower·value·to·be·safe·(~23·days).57 #·sqlite3_busy_timeout()·accepts·a·C·int,·max·2_147_483_647·on·32-bit.·Use·a·lower·value·to·be·safe·(~23·days).
43 _MAX_SQLITE_TIMEOUT_MS:·Final[int]·=·2_000_000_000·-·158 _MAX_SQLITE_TIMEOUT_MS:·Final[int]·=·2_000_000_000·-·1
44 _UNSAFE_FORK_EXIT_STATUS:·Final[int]·=·7059 _UNSAFE_FORK_EXIT_STATUS:·Final[int]·=·70
 60 #·O_NONBLOCK·keeps·an·open·from·blocking·on·a·FIFO·planted·at·the·path;·the·regular-file·check·then·rejects·it.
 61 _DB_OPEN_FLAGS:·Final[int]·=·os.O_RDWR·|·os.O_CREAT·|·getattr(os,·"O_NOFOLLOW",·0)·|·getattr(os,·"O_NONBLOCK",·0)
 62 #·Descriptor·paths·reopen·the·validated·inode;·journal_mode=MEMORY·avoids·an·on-disk·journal·at·the·synthetic·path.
 63 _FD_DIR:·Final[str]·=·"/proc/self/fd"·if·sys.platform·==·"linux"·else·"/dev/fd"
 64 #·Header·bytes·18·and·19·hold·the·file·format·versions,·2·in·WAL·mode:·https://www.sqlite.org/fileformat.html
 65 _SQLITE_MAGIC:·Final[bytes]·=·b"SQLite·format·3\x00"
 66 _FORMAT_VERSIONS:·Final[slice]·=·slice(18,·20)
 67 _HEADER_SIZE:·Final[int]·=·20
 68 _WAL_FORMAT_VERSION:·Final[int]·=·2
  
  
45 class·_SQLiteTransitionContext(threading.local):69 class·_SQLiteTransitionContext(threading.local):
46 ····depth:·int·=·070 ····depth:·int·=·0
  
  
47 _SQLITE_TRANSITION_CONTEXT:·Final·=·_SQLiteTransitionContext()71 _SQLITE_TRANSITION_CONTEXT:·Final·=·_SQLiteTransitionContext()
Offset 130, 51 lines modifiedOffset 154, 176 lines modified
130 ········except·OSError:154 ········except·OSError:
131 ············return·None155 ············return·None
132 ········return·stat_result.st_dev,·stat_result.st_ino156 ········return·stat_result.st_dev,·stat_result.st_ino
  
  
133 _FORKED_DATABASES:·Final·=·_ForkedDatabaseRegistry()157 _FORKED_DATABASES:·Final·=·_ForkedDatabaseRegistry()
  
 158 _LINK_PREFIX:·Final[str]·=·".filelock-"
 159 _SWEPT_DIRECTORIES:·Final[set[str]]·=·set()
  
  
 160 #·POSIX·locks·belong·to·the·process·and·the·inode,·so·closing·any·descriptor·on·the·inode·drops·the·locks·every·other
 161 #·connection·of·this·process·holds·there.·SQLite·defers·its·own·closes·for·this·reason·(section·2.2·of
 162 #·https://www.sqlite.org/howtocorrupt.html);·the·probes·stay·open·until·the·last·connection·on·their·inode·closes.
 163 class·_ProbeDescriptors:
 164 ····def·__init__(self)·->·None:
 165 ········self._lock·=·threading.Lock()
 166 ········self._inodes:·dict[_DatabaseIdentity,·_InodeProbes]·=·{}
 167 ········self._releases:·deque[_Probe]·=·deque()
 168 ········self._leases·=·count()
  
 169 ····def·adopt(self,·database:·str,·claimed:·list[_Probe])·->·_Probe·|·None:··#·pragma:·win32·no·cover
 170 ········#·Reuse·a·probe·no·live·connection·holds:·each·connect·would·otherwise·keep·another·descriptor·open·until·the
 171 ········#·inode's·last·close,·and·two·live·connections·through·one·/dev/fd·name·make·macOS·SQLite·fail·to·open.
 172 ········try:
 173 ············stat_result:·Final·=·os.lstat(database)
 174 ········except·OSError:
 175 ············return·None
 176 ········identity:·Final·=·stat_result.st_dev,·stat_result.st_ino
 177 ········with·self._lock:
 178 ············if·not·stat.S_ISREG(stat_result.st_mode)·or·not·(probes·:=·self._inodes.get(identity))·or·not·probes.idle:
 179 ················return·None
 180 ············claimed.append(adopted·:=·_Probe(identity,·probes.idle.pop(),·next(self._leases)))
 181 ············probes.leases.add(adopted.lease)
 182 ········return·adopted
  
 183 ····def·retain(self,·fd:·int,·claimed:·list[_Probe])·->·_Probe:··#·pragma:·win32·no·cover
 184 ········stat_result:·Final·=·os.fstat(fd)
 185 ········identity:·Final·=·stat_result.st_dev,·stat_result.st_ino
 186 ········token:·Final·=·_register_owned_descriptor(fd,·identity)
 187 ········with·self._lock:
 188 ············(probes·:=·self._inodes.setdefault(identity,·_InodeProbes())).descriptors.append((fd,·token))
 189 ············claimed.append(retained·:=·_Probe(identity,·fd,·next(self._leases)))
 190 ············probes.leases.add(retained.lease)
 191 ········return·retained
  
Max diff block lines reached; 36019/44199 bytes (81.49%) of diff not shown.
⊟
18.0 KB
filelock/_soft.py
    
Offset 2, 23 lines modifiedOffset 2, 24 lines modified
  
2 import·os2 import·os
3 import·stat3 import·stat
4 import·sys4 import·sys
5 import·time5 import·time
6 from·contextlib·import·suppress6 from·contextlib·import·suppress
7 from·errno·import·EACCES,·EEXIST,·EPERM7 from·errno·import·EACCES,·EEXIST,·EPERM
 8 from·itertools·import·islice
8 from·pathlib·import·Path9 from·pathlib·import·Path
9 from·typing·import·Final10 from·typing·import·Final
  
10 from·._api·import·BaseFileLock,·_raise_grouped_errors11 from·._api·import·BaseFileLock,·_raise_grouped_errors
11 from·._identity·import·host_name,·owner_is_stale,·process_start_token12 from·._identity·import·host_name,·owner_is_current_process,·owner_is_stale,·process_start_token
12 from·._soft_protocol·import·STRICT_SOFT_SENTINEL_RECORD13 from·._soft_protocol·import·STRICT_SOFT_SENTINEL_RECORD
13 from·._util·import·break_lock_file,·ensure_directory_exists,·raise_on_not_writable_file,·write_all14 from·._util·import·break_lock_file,·ensure_directory_exists,·raise_on_not_writable_file,·write_all
  
14 _MALFORMED_LOCK_AGE_THRESHOLD:·Final[float]·=·2.015 MALFORMED_LOCK_AGE_THRESHOLD:·Final[float]·=·2.0
15 _MAX_LOCK_FILE_SIZE:·Final[int]·=·102416 _MAX_LOCK_FILE_SIZE:·Final[int]·=·1024
16 _UNLINK_MAX_RETRIES:·Final[int]·=·1017 _UNLINK_MAX_RETRIES:·Final[int]·=·10
17 _MARKER_WITH_START_TOKEN_LINE_COUNT:·Final[int]·=·318 _MARKER_WITH_START_TOKEN_LINE_COUNT:·Final[int]·=·3
  
  
18 class·SoftFileLock(BaseFileLock):19 class·SoftFileLock(BaseFileLock):
19 ····"""20 ····"""
Offset 44, 15 lines modifiedOffset 45, 25 lines modified
  
44 ····#:·An·existence·lock·unlinks·its·marker·to·release,·so·it·cannot·promise·to·keep·the·pathname.45 ····#:·An·existence·lock·unlinks·its·marker·to·release,·so·it·cannot·promise·to·keep·the·pathname.
45 ····_preserve_lock_file_supported:·bool·=·False46 ····_preserve_lock_file_supported:·bool·=·False
  
46 ····#:·An·existence·lock·keeps·protocol·state·in·its·marker,·so·it·cannot·lend·the·descriptor·to·an·on_acquired·hook.47 ····#:·An·existence·lock·keeps·protocol·state·in·its·marker,·so·it·cannot·lend·the·descriptor·to·an·on_acquired·hook.
47 ····_on_acquired_supported:·bool·=·False48 ····_on_acquired_supported:·bool·=·False
  
 49 ····#:·The·marker's·(mtime,·inode)·when·this·instance·last·saw·it·change,·and·when·that·was·on·its·monotonic·clock.
 50 ····_marker_seen:·tuple[tuple[float,·int],·float]·|·None·=·None
  
 51 ····#:·The·identity·of·a·marker·a·Windows·release·relinquished·but·has·not·unlinked·yet.
 52 ····_marker_cleanup:·tuple[int,·int]·|·None·=·None
  
 53 ····#:·The·descriptor·of·that·marker·while·its·close·has·not·run·yet,·as·a·list·so·one·C·call·can·take·it.
 54 ····_marker_fds:·list[int]
  
48 ····def·_acquire(self)·->·None:55 ····def·_acquire(self)·->·None:
 56 ········self._finish_marker_cleanup()
49 ········raise_on_not_writable_file(self.lock_file)57 ········raise_on_not_writable_file(self.lock_file)
50 ········ensure_directory_exists(self.lock_file)58 ········ensure_directory_exists(self.lock_file)
51 ········#·O_CREAT·|·O_EXCL·makes·the·create·fail·with·EEXIST·when·the·file·already·exists,·so·a·successful·open59 ········#·O_CREAT·|·O_EXCL·makes·the·create·fail·with·EEXIST·when·the·file·already·exists,·so·a·successful·open
52 ········#·means·this·process·now·holds·the·lock.60 ········#·means·this·process·now·holds·the·lock.
53 ········flags·=·os.O_WRONLY·|·os.O_CREAT·|·os.O_EXCL·|·os.O_TRUNC61 ········flags·=·os.O_WRONLY·|·os.O_CREAT·|·os.O_EXCL·|·os.O_TRUNC
54 ········if·(o_nofollow·:=·getattr(os,·"O_NOFOLLOW",·None))·is·not·None:··#·pragma:·needs·o-nofollow62 ········if·(o_nofollow·:=·getattr(os,·"O_NOFOLLOW",·None))·is·not·None:··#·pragma:·needs·o-nofollow
55 ············flags·|=·o_nofollow63 ············flags·|=·o_nofollow
Offset 71, 42 lines modifiedOffset 82, 70 lines modified
71 ····def·_publish_held_marker(self,·fd:·int)·->·None:82 ····def·_publish_held_marker(self,·fd:·int)·->·None:
72 ········#·Publish·held·state·only·once·the·record·is·fully·on·disk.·On·any·failure,·including·cancellation,·close·the83 ········#·Publish·held·state·only·once·the·record·is·fully·on·disk.·On·any·failure,·including·cancellation,·close·the
73 ········#·descriptor·and·unlink·the·path·only·while·it·still·names·the·file·we·opened,·so·a·rollback·never·deletes·a84 ········#·descriptor·and·unlink·the·path·only·while·it·still·names·the·file·we·opened,·so·a·rollback·never·deletes·a
74 ········#·successor's·marker·that·replaced·ours·at·the·same·path·after·our·lease·expired.85 ········#·successor's·marker·that·replaced·ours·at·the·same·path·after·our·lease·expired.
75 ········identity:·tuple[int,·int]·|·None·=·None86 ········identity:·tuple[int,·int]·|·None·=·None
76 ········try:87 ········try:
77 ············identity·=·_file_identity(os.fstat(fd))88 ············identity·=·_file_identity(os.fstat(fd))
 89 ············self._apply_explicit_mode(fd)
78 ············self._write_lock_info(fd)90 ············self._write_lock_info(fd)
79 ········except·BaseException:91 ········except·BaseException:
80 ············self._mark_descriptor_released()92 ············self._mark_descriptor_released()
 93 ············try:
81 ············os.close(fd)94 ················os.close(fd)
 95 ············finally:
 96 ················self._unlink_held_marker(identity)
82 ············with·suppress(OSError): 
83 ················if·identity·is·not·None·and·_file_identity(os.lstat(self.lock_file))·==·identity: 
84 ····················Path(self.lock_file).unlink() 
85 ············raise97 ············raise
86 ········self._mark_descriptor_owned(fd,·identity)98 ········self._mark_descriptor_owned(fd,·identity)
  
 99 ····def·_apply_explicit_mode(self,·fd:·int)·->·None:
 100 ········#·os.open·filters·the·mode·through·the·umask,·so·an·explicit·mode·lands·as·given·only·through·fchmod,·the·way
 101 ········#·UnixFileLock·applies·it.·Windows·maps·the·mode·to·a·read-only·bit·that·os.open·already·set.
 102 ········if·self.has_explicit_mode·and·sys.platform·!=·"win32":··#·pragma:·win32·no·cover
 103 ············with·suppress(PermissionError):
 104 ················os.fchmod(fd,·self._context.mode)
  
87 ····def·_try_break_stale_lock(self)·->·None:105 ····def·_try_break_stale_lock(self)·->·None:
88 ········with·suppress(OSError,·ValueError):106 ········with·suppress(OSError,·ValueError):
89 ············content,·mtime,·ino·=·_read_lock_file(self.lock_file)107 ············content,·mtime,·ino·=·_read_lock_file(self.lock_file)
90 ············if·content·==·STRICT_SOFT_SENTINEL_RECORD:··#·pragma:·needs·hard-link108 ············if·content·==·STRICT_SOFT_SENTINEL_RECORD:··#·pragma:·needs·hard-link
91 ················return109 ················return
92 ············holder·=·_parse_lock_holder(content)110 ············holder·=·_parse_lock_holder(content)
  
93 ············if·holder·is·None:111 ············if·holder·is·None:
94 ················#·Unparsable:·wrong·line·count,·a·non-integer·PID·or·start·token,·empty,·oversized·or·not·UTF-8.112 ················#·Unparsable:·wrong·line·count,·a·non-integer·PID·or·start·token,·empty,·oversized·or·not·UTF-8.
95 ················#·Self-heal·only·once·the·file·is·clearly·not·a·half-written·fresh·lock·(a·peer·between·O_EXCL·and113 ················#·Self-heal·only·once·the·file·is·clearly·not·a·half-written·fresh·lock·(a·peer·between·O_EXCL·and
96 ················#·_write_lock_info),·so·the·brief·create-then-write·window·is·never·mistaken·for·a·stale·lock.114 ················#·_write_lock_info),·so·the·brief·create-then-write·window·is·never·mistaken·for·a·stale·lock.
97 ················if·time.time()·-·mtime·>=·_MALFORMED_LOCK_AGE_THRESHOLD:115 ················if·self._marker_unchanged_for(mtime,·ino)·>=·MALFORMED_LOCK_AGE_THRESHOLD:
98 ····················break_lock_file(self.lock_file,·mtime,·ino)116 ····················break_lock_file(self.lock_file,·mtime,·ino)
99 ················return117 ················return
  
100 ············if·owner_is_stale(*holder):118 ············if·owner_is_stale(*holder):
101 ················break_lock_file(self.lock_file,·mtime,·ino)119 ················break_lock_file(self.lock_file,·mtime,·ino)
  
 120 ····def·_marker_unchanged_for(self,·mtime:·float,·ino:·int)·->·float:
 121 ········#·The·mtime·is·the·writer's·or·file·server's·clock,·so·against·time.time()·a·contender·whose·clock·runs·ahead
 122 ········#·would·expire·a·fresh·marker.·Only·watch·it·for·change,·timed·on·this·process's·monotonic·clock.
 123 ········now:·Final·=·time.monotonic()
 124 ········if·(seen·:=·self._marker_seen)·is·None·or·seen[0]·!=·(mtime,·ino):
 125 ············self._marker_seen·=·(mtime,·ino),·now
 126 ············return·0.0
 127 ········return·now·-·seen[1]
  
 128 ····def·_unprobeable_holder(self)·->·str·|·None:
 129 ········#·This·host·cannot·prove·such·a·holder·dead,·so·whoever·decides·whether·it·is·gone·needs·its·name.
 130 ········with·suppress(OSError,·ValueError):
 131 ············if·(holder·:=·self._recorded_holder(_read_lock_file(self.lock_file)[0]))·and·holder[1]·!=·host_name():
 132 ················return·f"pid·{holder[0]}·on·{holder[1]}"
 133 ········return·None
  
 134 ····@classmethod
 135 ····def·_recorded_holder(cls,·content:·str·|·None)·->·tuple[int,·str]·|·None:
 136 ········return·None·if·(holder·:=·_parse_lock_holder(content))·is·None·else·holder[:2]
  
102 ····@staticmethod137 ····@staticmethod
103 ····def·_write_lock_info(fd:·int)·->·None:138 ····def·_write_lock_info(fd:·int)·->·None:
104 ········#·No·suppression:·a·write·failure·must·reach·the·acquisition·rollback·so·it·never·publishes·a·half-written139 ········#·No·suppression:·a·write·failure·must·reach·the·acquisition·rollback·so·it·never·publishes·a·half-written
105 ········#·marker·as·held·state.·The·optional·third·line·is·this·process's·start·token,·absent·when·the·platform140 ········#·marker·as·held·state.·The·optional·third·line·is·this·process's·start·token,·absent·when·the·platform
106 ········#·exposes·no·proven·start·time,·in·which·case·a·reader·falls·back·to·PID-only·liveness.141 ········#·exposes·no·proven·start·time,·in·which·case·a·reader·falls·back·to·PID-only·liveness.
107 ········info·=·f"{os.getpid()}\n{host_name()}\n"142 ········info·=·f"{os.getpid()}\n{host_name()}\n"
108 ········if·(token·:=·process_start_token(os.getpid()))·is·not·None:143 ········if·(token·:=·process_start_token(os.getpid()))·is·not·None:
Offset 128, 83 lines modifiedOffset 167, 144 lines modified
128 ········return·None167 ········return·None
  
Max diff block lines reached; 11916/18419 bytes (64.69%) of diff not shown.
⊟
34.8 KB
filelock/_strict.py
    
Offset 1, 32 lines modifiedOffset 1, 36 lines modified
1 from·__future__·import·annotations1 from·__future__·import·annotations
  
2 import·contextlib2 import·contextlib
3 import·errno3 import·errno
 4 import·functools
4 import·os5 import·os
5 import·secrets6 import·secrets
6 import·stat7 import·stat
7 import·sys8 import·sys
8 import·tempfile9 import·tempfile
9 import·time10 import·time
10 from·dataclasses·import·dataclass11 from·dataclasses·import·dataclass
11 from·errno·import·EACCES,·EEXIST,·ENOENT,·ENOSYS,·EPERM,·ESTALE,·EXDEV12 from·errno·import·EACCES,·EEXIST,·ENOENT,·ENOSYS,·EPERM,·ESTALE,·EXDEV
12 from·pathlib·import·Path13 from·pathlib·import·Path
13 from·typing·import·TYPE_CHECKING,·Final,·Literal,·cast14 from·typing·import·TYPE_CHECKING,·Final,·Literal,·cast
  
14 from·._api·import·BaseFileLock,·_canonical,·_raise_cleanup_errors15 from·._api·import·BaseFileLock,·ThreadLocalFileContext,·_canonical,·_raise_cleanup_errors
15 from·._error·import·SoftFileLockProtocolError16 from·._error·import·SoftFileLockProtocolError
16 from·._identity·import·host_name,·process_start_token17 from·._identity·import·host_name,·owner_is_stale,·process_start_token
 18 from·._marker·import·parse_marker
 19 from·._soft·import·MALFORMED_LOCK_AGE_THRESHOLD,·_parse_lock_holder
17 from·._soft_protocol·import·STRICT_SOFT_SENTINEL_RECORD20 from·._soft_protocol·import·STRICT_SOFT_SENTINEL_RECORD
18 from·._util·import·ensure_directory_exists,·write_all21 from·._util·import·ensure_directory_exists,·write_all
  
19 if·TYPE_CHECKING:22 if·TYPE_CHECKING:
20 ····from·collections.abc·import·Iterator23 ····from·collections.abc·import·Callable,·Iterator
  
21 StrictSoftFileClaimState·=·Literal["intent",·"held"]24 StrictSoftFileClaimState·=·Literal["intent",·"held"]
 25 _OccupantState·=·Literal["sentinel",·"held",·"exited",·"damaged",·"unparsable"]
  
22 _CLAIM_STATES:·Final[frozenset[str]]·=·frozenset({"intent",·"held"})26 _CLAIM_STATES:·Final[frozenset[str]]·=·frozenset({"intent",·"held"})
23 _COORDINATION_SUFFIX:·Final[str]·=·".filelock"27 _COORDINATION_SUFFIX:·Final[str]·=·".filelock"
24 _CLAIM_DIRECTORY_NAME:·Final[str]·=·"claims"28 _CLAIM_DIRECTORY_NAME:·Final[str]·=·"claims"
25 _CLAIM_MAGIC:·Final[str]·=·"filelock-strict-v1"29 _CLAIM_MAGIC:·Final[str]·=·"filelock-strict-v1"
26 _CLAIM_RECORD_LIMIT:·Final[int]·=·102430 _CLAIM_RECORD_LIMIT:·Final[int]·=·1024
27 _CLAIM_NAME_PART_COUNT:·Final[int]·=·331 _CLAIM_NAME_PART_COUNT:·Final[int]·=·3
Offset 35, 14 lines modifiedOffset 39, 17 lines modified
35 _PRIVATE_RECORD_SUFFIX:·Final[str]·=·".tmp"39 _PRIVATE_RECORD_SUFFIX:·Final[str]·=·".tmp"
36 _PRIVATE_RECORD_RANDOM_HEX_LENGTH:·Final[int]·=·3240 _PRIVATE_RECORD_RANDOM_HEX_LENGTH:·Final[int]·=·32
37 _PRIVATE_RECORD_GRACE:·Final[float]·=·2.041 _PRIVATE_RECORD_GRACE:·Final[float]·=·2.0
38 _UNLINK_MAX_RETRIES:·Final[int]·=·1042 _UNLINK_MAX_RETRIES:·Final[int]·=·10
39 #:·How·long·a·scan·waits·out·a·claim·held·in·Windows'·delete-pending·state·before·treating·it·as·unreadable.43 #:·How·long·a·scan·waits·out·a·claim·held·in·Windows'·delete-pending·state·before·treating·it·as·unreadable.
40 _CLAIM_READ_GRACE:·Final[float]·=·0.544 _CLAIM_READ_GRACE:·Final[float]·=·0.5
41 _CLAIM_READ_RETRY:·Final[float]·=·0.00245 _CLAIM_READ_RETRY:·Final[float]·=·0.002
 46 #:·Rides·out·a·peer·replacing·the·lock·path·mid-inspection;·a·foreign·node·or·unreadable·record·outlasting·it·is·damage.
 47 _SENTINEL_READ_GRACE:·Final[float]·=·0.5
 48 _NODE_DESCRIPTIONS:·Final[dict[int,·str]]·=·{stat.S_IFDIR:·"a·directory",·stat.S_IFLNK:·"a·symlink"}
42 #:·Windows·opens·descriptors·in·text·mode·by·default,·which·rewrites·newlines·and·truncates·a·record·at·a·control·byte.49 #:·Windows·opens·descriptors·in·text·mode·by·default,·which·rewrites·newlines·and·truncates·a·record·at·a·control·byte.
43 #:·The·claim·and·sentinel·records·are·exact·binary,·so·every·record·descriptor·must·be·binary;·POSIX·ignores·the·flag.50 #:·The·claim·and·sentinel·records·are·exact·binary,·so·every·record·descriptor·must·be·binary;·POSIX·ignores·the·flag.
44 _O_BINARY:·Final[int]·=·getattr(os,·"O_BINARY",·0)51 _O_BINARY:·Final[int]·=·getattr(os,·"O_BINARY",·0)
45 _LEGACY_SENTINEL:·Final[bytes]·=·STRICT_SOFT_SENTINEL_RECORD.encode()52 _LEGACY_SENTINEL:·Final[bytes]·=·STRICT_SOFT_SENTINEL_RECORD.encode()
46 _WINDOWS_HARD_LINK_UNSUPPORTED:·Final[frozenset[int]]·=·frozenset({1,·17,·50})53 _WINDOWS_HARD_LINK_UNSUPPORTED:·Final[frozenset[int]]·=·frozenset({1,·17,·50})
  
47 #·Termux/Android·CPython·ships·without·os.link·(bionic·long·had·only·linkat),·so·the·strict·backend's·whole·hard-link54 #·Termux/Android·CPython·ships·without·os.link·(bionic·long·had·only·linkat),·so·the·strict·backend's·whole·hard-link
Offset 97, 135 lines modifiedOffset 104, 184 lines modified
  
97 ····_preserve_lock_file_supported:·bool·=·True104 ····_preserve_lock_file_supported:·bool·=·True
98 ····_on_acquired_supported:·bool·=·False105 ····_on_acquired_supported:·bool·=·False
99 ····#:·Age·cannot·clear·a·strict·claim:·expiring·one·on·a·clock·is·the·overlap·the·fail-closed·contract·exists·to·rule106 ····#:·Age·cannot·clear·a·strict·claim:·expiring·one·on·a·clock·is·the·overlap·the·fail-closed·contract·exists·to·rule
100 ····#:·out,·so·only·force_break()·removes·it.107 ····#:·out,·so·only·force_break()·removes·it.
101 ····_lifetime_supported:·bool·=·False108 ····_lifetime_supported:·bool·=·False
102 ····_lifetime_unsupported_reason:·str·=·"a·strict·claim·is·never·broken·by·age,·only·by·force_break()"109 ····_lifetime_unsupported_reason:·str·=·"a·strict·claim·is·never·broken·by·age,·only·by·force_break()"
103 ····#:·The·claim·doorway·publishes·an·intent·and·a·held·record·per·owner,·so·a·shared·instance·must·serialize·them. 
104 ····_serialize_transitions:·bool·=·True 
105 ····#:·Contending·processes·each·publish·and·rescan·several·files,·so·back·their·retries·off·across·a·jittered·window110 ····#:·Contending·processes·each·publish·and·rescan·several·files,·so·jitter·their·retries.·Seconds.·Only·a
106 ····#:·rather·than·let·them·collide·on·every·poll.·Seconds;·keeps·a·waiter·responsive·once·it·wins.111 ····#:·poll_interval·below·this·cap·jitters;·the·default·equals·it·and·keeps·a·fixed·cadence.
107 ····_poll_backoff_cap:·float·=·0.05112 ····_poll_backoff_cap:·float·=·0.05
 113 ····_occupant_seen:·tuple[tuple[float,·int,·int],·float]·|·None·=·None
  
108 ····def·_acquire(self)·->·None:114 ····def·_acquire(self)·->·None:
 115 ········#·Finish·a·doorway·whose·claim·cleanup·failed·before·publishing,·so·this·owner·never·contends·with·leftovers.
 116 ········self._discard_pending_doorways(exited_only=True)
109 ········#·Resolve·once·per·acquisition,·not·per·poll:·a·waiter·on·a·relative·path·must·keep·publishing·into·the117 ········#·Resolve·once·per·acquisition,·not·per·poll:·a·waiter·on·a·relative·path·must·keep·publishing·into·the
110 ········#·directory·it·started·waiting·in·even·when·another·thread·changes·the·working·directory·mid-wait.118 ········#·directory·it·started·waiting·in·even·when·another·thread·changes·the·working·directory·mid-wait.
111 ········if·(claim_root·:=·self._context.claim_root)·is·None:119 ········if·(claim_root·:=·self._context.claim_root)·is·None:
112 ············claim_root·=·self._context.claim_root·=·_canonical(self.lock_file)120 ············claim_root·=·self._context.claim_root·=·_canonical(self.lock_file)
113 ········lock_path·=·Path(claim_root)121 ········lock_path·=·Path(claim_root)
114 ········coordination_directory·=·Path(f"{lock_path}{_COORDINATION_SUFFIX}")122 ········coordination_directory·=·Path(f"{lock_path}{_COORDINATION_SUFFIX}")
115 ········claim_directory·=·coordination_directory·/·_CLAIM_DIRECTORY_NAME123 ········claim_directory·=·coordination_directory·/·_CLAIM_DIRECTORY_NAME
116 ········ensure_directory_exists(os.fspath(lock_path))124 ········ensure_directory_exists(os.fspath(lock_path))
117 ········_ensure_protocol_directory(self.lock_file,·coordination_directory)125 ········_ensure_protocol_directory(self.lock_file,·coordination_directory)
118 ········_ensure_protocol_directory(self.lock_file,·claim_directory)126 ········_ensure_protocol_directory(self.lock_file,·claim_directory)
119 ········if·(sentinel_fd·:=·_open_or_create_sentinel(self.lock_file,·lock_path,·self._open_mode()))·is·None:127 ········if·(
 128 ············sentinel_fd·:=·_open_or_create_sentinel(
 129 ················self.lock_file,·lock_path,·self._open_mode(),·self._occupant_unchanged_for
 130 ············)
 131 ········)·is·None:
120 ············return132 ············return
121 ········try:133 ········try:
122 ············sentinel_identity·=·_file_identity(os.fstat(sentinel_fd))134 ············sentinel_identity·=·_file_identity(os.fstat(sentinel_fd))
123 ········except·BaseException·as·inspection_error:··#·preserve·inspection·and·descriptor·cleanup·errors135 ········except·BaseException·as·inspection_error:··#·preserve·inspection·and·descriptor·cleanup·errors
124 ············try:136 ············try:
125 ················os.close(sentinel_fd)137 ················os.close(sentinel_fd)
126 ············except·BaseException·as·close_error:··#·ruff:ignore[blind-except]··#·preserve·inspection·and·descriptor·cleanup·errors138 ············except·BaseException·as·close_error:··#·ruff:ignore[blind-except]··#·preserve·inspection·and·descriptor·cleanup·errors
127 ················_raise_cleanup_errors("strict·sentinel·inspection·cleanup·failed",·inspection_error,·close_error)139 ················_raise_cleanup_errors("strict·sentinel·inspection·cleanup·failed",·inspection_error,·close_error)
128 ············raise140 ············raise
129 ········self._mark_descriptor_pending(sentinel_fd,·sentinel_identity)141 ········self._mark_descriptor_pending(sentinel_fd,·sentinel_identity)
130 ········try:142 ········try:
131 ············self._attempt_doorway(claim_directory,·sentinel_fd,·sentinel_identity)143 ············won·=·self._attempt_doorway(claim_directory)
132 ········except·BaseException:144 ········except·BaseException:
 145 ············self._discard_doorway()
133 ············if·self._context.pending_lock_file_fd·==·sentinel_fd: 
134 ················self._discard_doorway(sentinel_fd,·sentinel_identity) 
135 ············raise146 ············raise
 147 ········if·won:
 148 ············self._mark_descriptor_owned(sentinel_fd,·sentinel_identity)
 149 ········else:
 150 ············self._discard_doorway()
  
136 ····def·_attempt_doorway(self,·claim_directory:·Path,·sentinel_fd:·int,·sentinel_identity:·tuple[int,·int])·->·None: 
137 ········if·_read_existing_claims(self.lock_file,·claim_directory): 
138 ············self._discard_doorway(sentinel_fd,·sentinel_identity)151 ····def·_discard_pending_doorways(self,·*,·exited_only:·bool)·->·None:
 152 ········if·self._context.owner_claim_paths·and·not·self.is_locked:
 153 ············self._discard_doorway()
 154 ········if·not·isinstance(context·:=·self._context,·ThreadLocalFileContext):
139 ············return155 ············return
 156 ········#·Only·this·registry·reaches·an·exited·thread's·thread-local·doorway;·a·live·thread·finishes·its·own.
 157 ········own:·Final·=·context.current
 158 ········with·self._transition_lock:
 159 ············for·pending,·thread·in·self._thread_pending.copy().values():
 160 ················if·exited_only·and·thread.is_alive():
 161 ····················continue
 162 ················context.current·=·pending
 163 ················try:
 164 ····················self._discard_doorway()
 165 ················finally:
 166 ····················context.current·=·own
Max diff block lines reached; 27700/35573 bytes (77.87%) of diff not shown.
⊟
6.98 KB
filelock/_unix.py
    
Offset 63, 78 lines modifiedOffset 63, 85 lines modified
  
63 ········We·leave·the·lock·file·in·place·after·release.·Unlinking·a·locked·file·on·Unix·splits63 ········We·leave·the·lock·file·in·place·after·release.·Unlinking·a·locked·file·on·Unix·splits
64 ········waiters·across·inodes·and·breaks·mutual·exclusion·for·processes·that·coordinate·via·the64 ········waiters·across·inodes·and·breaks·mutual·exclusion·for·processes·that·coordinate·via·the
65 ········same·path.65 ········same·path.
66 ········"""66 ········"""
  
67 ········def·_acquire(self)·->·None:67 ········def·_acquire(self)·->·None:
68 ············missing_flock·=·self._acquire_native()68 ············if·(missing_flock·:=·self._acquire_native())·is·not·None:
69 ············if·missing_flock·is·not·None: 
70 ················self._switch_to_soft_lock(*missing_flock)69 ················fd,·exception,·created·=·missing_flock
 70 ················self._switch_to_soft_lock(fd,·exception,·created=created)
  
71 ········def·_acquire_native(self)·->·tuple[int,·OSError]·|·None:71 ········def·_acquire_native(self)·->·tuple[int,·OSError,·bool]·|·None:
72 ············ensure_directory_exists(self.lock_file)72 ············ensure_directory_exists(self.lock_file)
 73 ············if·(opened·:=·self._open_lock_file())·is·None:
73 ············#·Open·without·O_TRUNC·and·defer·truncation·and·fchmod·until·after·flock·succeeds:·a·contender·that·loses 
74 ············#·the·lock·must·not·truncate·the·holder's·file·(erasing·caller·diagnostics)·or·change·its·mode.·The·winner 
75 ············#·truncates·and·normalizes·mode·once·it·owns·the·lock·(#591). 
76 ············open_flags·=·os.O_RDWR 
77 ············if·(o_nofollow·:=·getattr(os,·"O_NOFOLLOW",·None))·is·not·None: 
78 ················open_flags·|=·o_nofollow 
79 ············open_flags·|=·os.O_CREAT 
80 ············open_mode·=·self._open_mode() 
81 ············try: 
82 ················fd·=·os.open(self.lock_file,·open_flags,·open_mode) 
83 ············except·FileNotFoundError: 
84 ················#·On·FUSE/NFS,·os.open(O_CREAT)·is·not·atomic;·a·split·LOOKUP·+·CREATE·lets·a·concurrent·unlink() 
85 ················#·delete·the·file·between·them.·For·a·valid·path,·treat·ENOENT·as·transient·contention.·For·an 
86 ················#·invalid·path·(e.g.·empty·string),·re-raise·to·avoid·an·infinite·retry·loop. 
87 ················if·self.lock_file·and·Path(self.lock_file).parent.exists(): 
88 ····················return·None74 ················return·None
 75 ············fd,·created·=·opened
89 ················raise 
90 ············except·PermissionError: 
91 ················#·Sticky-bit·dirs·(e.g.·/tmp):·O_CREAT·fails·if·the·file·is·owned·by·another·user·(#317). 
92 ················#·Fall·back·to·opening·the·existing·file·without·O_CREAT. 
93 ················if·not·Path(self.lock_file).exists(): 
94 ····················raise 
95 ················try: 
96 ····················fd·=·os.open(self.lock_file,·open_flags·&·~os.O_CREAT,·open_mode) 
97 ················except·FileNotFoundError: 
98 ····················return·None 
99 ············self._mark_descriptor_pending(fd)76 ············self._mark_descriptor_pending(fd)
100 ············try:77 ············try:
101 ················locked·=·_lock_fd_nonblocking(fd)78 ················locked·=·_lock_fd_nonblocking(fd)
102 ············except·OSError·as·exception:79 ············except·OSError·as·exception:
103 ················if·exception.errno·!=·ENOSYS:80 ················if·exception.errno·!=·ENOSYS:
104 ····················self._mark_descriptor_released()81 ····················self._mark_descriptor_released()
105 ····················os.close(fd)82 ····················os.close(fd)
106 ····················raise··#·contention·returns·False·from·_lock_fd_nonblocking,·so·any·raise·here·is·a·real·failure83 ····················raise··#·contention·returns·False·from·_lock_fd_nonblocking,·so·any·raise·here·is·a·real·failure
107 ················return·fd,·exception84 ················return·fd,·exception,·created
108 ············if·locked:85 ············if·locked:
109 ················self._finalize_locked_fd(fd)86 ················self._finalize_locked_fd(fd)
110 ············else:87 ············else:
111 ················self._mark_descriptor_released()88 ················self._mark_descriptor_released()
112 ················os.close(fd)··#·contention;·let·the·retry·loop·try·again89 ················os.close(fd)··#·contention;·let·the·retry·loop·try·again
113 ············return·None90 ············return·None
  
 91 ········def·_open_lock_file(self)·->·tuple[int,·bool]·|·None:
 92 ············#·No·O_TRUNC:·a·contender·that·loses·the·flock·must·not·truncate·the·holder's·file·or·change·its·mode;·the
 93 ············#·winner·does·both·once·it·owns·the·lock·(#591).·O_EXCL·tells·the·ENOSYS·fallback·whether·this·attempt·made
 94 ············#·the·inode,·so·it·removes·only·its·own·placeholder,·never·a·peer's·marker.
 95 ············open_flags·=·os.O_RDWR
 96 ············if·(o_nofollow·:=·getattr(os,·"O_NOFOLLOW",·None))·is·not·None:
 97 ················open_flags·|=·o_nofollow
 98 ············open_mode·=·self._open_mode()
 99 ············try:
 100 ················return·os.open(self.lock_file,·open_flags·|·os.O_CREAT·|·os.O_EXCL,·open_mode),·True
 101 ············except·FileExistsError:
 102 ················pass
 103 ············except·FileNotFoundError:
 104 ················#·On·FUSE/NFS·a·split·LOOKUP·+·CREATE·lets·a·concurrent·unlink()·race·the·create,·so·ENOENT·is·transient
 105 ················#·contention.·An·empty·or·separator-terminated·path·(Path()·strips·the·separator)·fails·this·way·on
 106 ················#·every·attempt·on·macOS,·so·re-raise·rather·than·retry·forever.
 107 ················if·self.lock_file·and·not·self.lock_file.endswith(os.sep)·and·Path(self.lock_file).parent.exists():
 108 ····················return·None
 109 ················raise
 110 ············except·PermissionError:
 111 ················#·Sticky-bit·dirs·(e.g.·/tmp):·O_CREAT·fails·if·another·user·owns·the·file·(#317).
 112 ················if·not·Path(self.lock_file).exists():
 113 ····················raise
 114 ············try:
 115 ················return·os.open(self.lock_file,·open_flags,·open_mode),·False
 116 ············except·FileNotFoundError:
 117 ················return·None··#·unlinked·since·the·create·attempt;·let·the·retry·loop·start·over
  
114 ········def·_switch_to_soft_lock(self,·fd:·int,·missing_flock:·OSError)·->·None:118 ········def·_switch_to_soft_lock(self,·fd:·int,·missing_flock:·OSError,·*,·created:·bool)·->·None:
115 ············#·The·filesystem·does·not·implement·flock.·Capture·the·opened·file's·identity·before·closing·so·the·cleanup119 ············#·The·filesystem·does·not·implement·flock.·Capture·the·opened·file's·identity·before·closing·so·the·cleanup
116 ············#·below·removes·only·this·attempt's·placeholder,·not·a·peer's·replacement.120 ············#·below·removes·only·this·attempt's·placeholder,·not·a·peer's·replacement.
117 ············identity:·tuple[int,·int]·|·None·=·None121 ············identity:·tuple[int,·int]·|·None·=·None
118 ············with·suppress(OSError):122 ············with·suppress(OSError):
119 ················identity·=·(fstat·:=·os.fstat(fd)).st_dev,·fstat.st_ino123 ················identity·=·(fstat·:=·os.fstat(fd)).st_dev,·fstat.st_ino
120 ············self._mark_descriptor_released()124 ············self._mark_descriptor_released()
121 ············os.close(fd)125 ············os.close(fd)
122 ············if·not·self._fallback_to_soft·or·self._preserve_lock_file·or·self._on_acquired·is·not·None:126 ············if·not·self._fallback_to_soft·or·self._preserve_lock_file·or·self._on_acquired·is·not·None:
123 ················#·Fail·closed:·the·caller·opted·out·of·existence-lock·semantics·(#603),·asked·to·preserve·the·pathname127 ················#·Fail·closed:·the·caller·opted·out·of·existence-lock·semantics·(#603),·asked·to·preserve·the·pathname
124 ················#·(#605),·or·set·an·on_acquired·hook·(#607),·none·of·which·a·soft·lock·can·honor.128 ················#·(#605),·or·set·an·on_acquired·hook·(#607),·none·of·which·a·soft·lock·can·honor.
125 ················raise·missing_flock129 ················raise·missing_flock
 130 ············#·A·file·this·attempt·did·not·create·may·be·a·peer's·live·marker;·the·soft·lock·ages·out·a·stale·empty·one.
 131 ············if·created:
126 ············with·suppress(OSError):132 ················with·suppress(OSError):
127 ················current·=·os.lstat(self.lock_file)133 ····················current·=·os.lstat(self.lock_file)
128 ················if·identity·==·(current.st_dev,·current.st_ino):134 ····················if·identity·==·(current.st_dev,·current.st_ino):
129 ····················Path(self.lock_file).unlink()135 ························Path(self.lock_file).unlink()
130 ············self._fallback_to_soft_lock()136 ············self._fallback_to_soft_lock()
131 ············self._acquire()137 ············self._acquire()
  
132 ········def·_finalize_locked_fd(self,·fd:·int)·->·None:138 ········def·_finalize_locked_fd(self,·fd:·int)·->·None:
133 ············#·Runs·with·the·flock·held.·Truncate·and·normalize·mode·under·a·guard·so·any·failure·closes·fd·rather·than139 ············#·Runs·with·the·flock·held.·Truncate·and·normalize·mode·under·a·guard·so·any·failure·closes·fd·rather·than
134 ············#·leaking·it·and·its·lock.·A·concurrent·_release()·may·have·unlinked·the·inode·between·our·open()·and140 ············#·leaking·it·and·its·lock.·A·concurrent·_release()·may·have·unlinked·the·inode·between·our·open()·and
135 ············#·flock()·(st_nlink·0),·leaving·a·useless·dead-inode·lock;·drop·it·and·let·the·retry·loop·start·fresh.141 ············#·flock()·(st_nlink·0),·leaving·a·useless·dead-inode·lock;·drop·it·and·let·the·retry·loop·start·fresh.
⊟
8.92 KB
filelock/_util.py
    
Offset 1, 25 lines modifiedOffset 1, 26 lines modified
1 from·__future__·import·annotations1 from·__future__·import·annotations
  
2 import·os2 import·os
3 import·secrets3 import·secrets
4 import·stat4 import·stat
5 import·sys5 import·sys
 6 from·contextlib·import·suppress
6 from·errno·import·EACCES,·EIO,·EISDIR7 from·errno·import·EACCES,·EIO,·EISDIR
7 from·pathlib·import·Path8 from·pathlib·import·Path
8 from·typing·import·Final9 from·typing·import·Final
  
  
9 def·write_all(fd:·int,·data:·bytes)·->·None:10 def·write_all(fd:·int,·data:·bytes)·->·None:
10 ····"""11 ····"""
11 ····Write·the·whole·buffer·to·*fd*,·looping·over·the·short·writes·``os.write``·is·allowed·to·make.12 ····Write·the·whole·buffer·to·*fd*,·looping·over·the·short·writes·POSIX·lets·``os.write``·make.
  
12 ····A·marker·written·with·a·bare·``os.write``·can·land·partially:·a·peer·reading·it·mid-write·parses·a·truncated·record 
13 ····as·malformed·or·as·a·foreign·holder.·Looping·until·the·buffer·drains·keeps·the·record·atomic·in·the·process·and 
14 ····kernel·view.·No·``fsync``:·filelock·needs·a·complete·record,·not·crash-durable·storage.13 ····A·caller·that·stopped·after·one·short·write·would·leave·a·truncated·marker·behind.·A·peer·that·reads·between·two
 14 ····writes·sees·a·prefix·of·the·record;·each·caller·has·to·tolerate·that.·Lock·records·need·not·survive·a·power·loss,·so
 15 ····we·skip·``fsync``.
  
15 ····:param·fd:·file·descriptor·open·for·writing.16 ····:param·fd:·file·descriptor·open·for·writing.
16 ····:param·data:·bytes·to·write·in·full.17 ····:param·data:·bytes·to·write·in·full.
  
17 ····:raises·OSError:·if·a·write·reports·zero·progress·before·the·record·is·complete.18 ····:raises·OSError:·if·a·write·reports·zero·progress·before·the·record·is·complete.
  
18 ····"""19 ····"""
Offset 49, 15 lines modifiedOffset 50, 23 lines modified
49 ········file_stat·=·os.lstat(filename)50 ········file_stat·=·os.lstat(filename)
50 ····except·OSError:51 ····except·OSError:
51 ········return··#·does·not·exist,·or·an·error·the·caller·cannot·act·on52 ········return··#·does·not·exist,·or·an·error·the·caller·cannot·act·on
  
52 ····#·No·mtime·guard:·the·old·`if·st_mtime·!=·0`·skip·covered·NFS/Linux·quirks·where·os.lstat·returned·an·all-zero53 ····#·No·mtime·guard:·the·old·`if·st_mtime·!=·0`·skip·covered·NFS/Linux·quirks·where·os.lstat·returned·an·all-zero
53 ····#·struct,·which·it·no·longer·does.·Skipping·on·mtime·0·let·a·read-only·file·or·a·directory·at·the·lock·path·pass54 ····#·struct,·which·it·no·longer·does.·Skipping·on·mtime·0·let·a·read-only·file·or·a·directory·at·the·lock·path·pass
54 ····#·as·missing,·so·acquire()·blocked·forever·on·an·open·that·cannot·succeed.55 ····#·as·missing,·so·acquire()·blocked·forever·on·an·open·that·cannot·succeed.
 56 ····#·Match·open()·credentials·where·supported;·group·permissions·and·ACLs·can·grant·access·without·S_IWUSR.
55 ····if·not·(file_stat.st_mode·&·stat.S_IWUSR):57 ····if·not·(file_stat.st_mode·&·stat.S_IWUSR)·and·not·os.access(
 58 ········filename,·os.W_OK,·effective_ids=os.access·in·os.supports_effective_ids
 59 ····):
 60 ········try:
 61 ············os.lstat(filename)
 62 ········except·FileNotFoundError:
 63 ············#·A·holder·may·unlink·its·marker·between·lstat()·and·access();·let·the·caller·attempt·creation.
 64 ············return
56 ········raise·PermissionError(EACCES,·"Permission·denied",·filename)65 ········raise·PermissionError(EACCES,·"Permission·denied",·filename)
  
57 ····if·stat.S_ISDIR(file_stat.st_mode):66 ····if·stat.S_ISDIR(file_stat.st_mode):
58 ········if·sys.platform·==·"win32":··#·pragma:·win32·cover67 ········if·sys.platform·==·"win32":··#·pragma:·win32·cover
59 ············raise·PermissionError(EACCES,·"Permission·denied",·filename)68 ············raise·PermissionError(EACCES,·"Permission·denied",·filename)
60 ········raise·IsADirectoryError(EISDIR,·"Is·a·directory",·filename)··#·pragma:·win32·no·cover69 ········raise·IsADirectoryError(EISDIR,·"Is·a·directory",·filename)··#·pragma:·win32·no·cover
  
Offset 70, 61 lines modifiedOffset 79, 66 lines modified
  
70 ····"""79 ····"""
71 ····Path(filename).parent.mkdir(parents=True,·exist_ok=True)80 ····Path(filename).parent.mkdir(parents=True,·exist_ok=True)
  
  
72 def·break_lock_file(lock_file:·str,·mtime_before:·float,·ino_before:·int)·->·None:81 def·break_lock_file(lock_file:·str,·mtime_before:·float,·ino_before:·int)·->·None:
73 ····"""82 ····"""
74 ····Atomically·break·a·stale·lock·file·judged·stale·at·modification·time·*mtime_before*.83 ····Remove·the·lock·file·a·caller·found·stale·with·modification·time·*mtime_before*·and·inode·*ino_before*.
  
75 ····Rename·the·file·to·a·process-private·name·before·unlinking·it,·so·two·processes·breaking·the·same·lock·cannot 
76 ····delete·each·other's·work:·only·one·rename·of·a·given·inode·wins,·the·loser·gets·``OSError``.·After·the·rename, 
77 ····re-check·the·file.·A·newer·modification·time,·or·a·different·inode·than·*ino_before*,·means·a·peer·recreated·the 
78 ····lock·between·the·stale·decision·and·the·rename,·so·we·grabbed·a·live·file·and·abort,·leaving·the·renamed·file·in 
79 ····place.·A·rollback·rename·is·itself·racy,·the·same·trade-off·as·the·soft·read/write·marker·break.·The·inode·check 
80 ····matters·because·filesystems·with·coarse·modification-time·granularity·(NFS,·FAT)·can·give·a·same-second·recreation 
81 ····the·old·mtime,·so·mtime·alone·would·miss·it·and·unlink·a·live·lock;·the·inode·is·the·reliable·identity,·mirroring 
82 ····the·token·re-check·in·the·soft·read/write·marker·break.·``lstat``·avoids·following·a·hostile·symlink·swapped·in 
83 ····after·the·decision.84 ····Right·before·renaming·we·``lstat``·the·lock·again·and·leave·it·alone·if·a·peer·recreated·it·since·the·caller·judged
 85 ····it·stale,·as·Mercurial·re-reads·a·lock·under·its·break·lock.·We·rename·before·unlinking·so·that,·of·several
 86 ····processes·racing·to·break·the·same·lock,·one·takes·the·file·and·the·rest·get·``OSError``.·A·newer·modification·time
 87 ····or·another·inode·on·the·renamed·file·means·a·peer·recreated·the·lock·between·that·``lstat``·and·the·rename,·so·we
 88 ····hard-link·it·back·and·drop·the·break·name.·``link``·never·replaces·a·name,·so·a·marker·a·third·process·created·after
 89 ····our·rename·wins·and·the·live·one·stays·under·the·break·name.·In·the·two·syscalls·between·rename·and·link·a·third
 90 ····process·can·acquire·beside·the·live·holder,·a·soft·lock·by·creating·its·marker·or·a·StrictSoftFileLock·by
 91 ····publishing·its·sentinel·at·the·empty·path.·Without·``os.link``,·or·on·a·filesystem·that·refuses·hard·links,·the·live
 92 ····marker·stays·under·the·break·name.·We·compare·inodes·as·well·as·modification·times·because·NFS·and·FAT·store
 93 ····coarse·modification·times,·and·a·peer·that·recreates·the·lock·within·that·granularity·leaves·the·old·mtime·on·it.
 94 ····We·call·``lstat``·to·avoid·following·a·symlink·a·peer·swaps·in·after·our·stale·check,·and·put·back·only·a·regular
 95 ····file·because·``link``·would·follow·a·symlink·to·its·target.
  
84 ····The·break·name·carries·a·random·token·so·it·is·unguessable·and·unique·per·attempt.·Without·it·two·breakers·in·the96 ····We·add·a·random·token·to·the·break·name·so·other·processes·cannot·guess·it·and·two·breakers·in·one·process·do·not
85 ····same·process·share·``<lock>.break.<pid>``,·and·a·second·break·can·rename·a·recreated·live·lock·onto·that·path·in97 ····share·``<lock>.break.<pid>``.·With·a·shared·name,·the·second·breaker·could·rename·a·recreated·live·lock·onto·that
 98 ····path·between·our·``lstat``·and·``unlink``,·and·our·``unlink``·would·delete·it.
86 ····the·window·between·the·re-verify·``lstat``·above·and·the·``unlink``·below,·deleting·a·live·lock·the·inode·check 
87 ····just·approved.·A·private·name·keeps·anyone·else·from·targeting·our·break·path,·matching·the·soft·read/write·marker 
88 ····break. 
  
89 ····:param·lock_file:·path·to·the·lock·file·to·break.99 ····:param·lock_file:·path·to·the·lock·file·to·break.
90 ····:param·mtime_before:·modification·time·observed·when·the·lock·was·judged·stale.100 ····:param·mtime_before:·modification·time·the·caller·saw·when·it·judged·the·lock·stale.
91 ····:param·ino_before:·inode·number·observed·when·the·lock·was·judged·stale.101 ····:param·ino_before:·inode·number·the·caller·saw·when·it·judged·the·lock·stale.
  
92 ····:raises·OSError:·if·the·rename·fails·(e.g.·the·file·vanished·or·is·not·owned·in·a·sticky·directory).102 ····:raises·OSError:·if·the·rename,·the·re-check·or·the·restore·fails,·for·example·because·the·file·vanished·or·another
 103 ········user·owns·it·in·a·sticky·directory.
  
93 ····"""104 ····"""
 105 ····if·(current·:=·os.lstat(lock_file)).st_mtime·>·mtime_before·or·current.st_ino·!=·ino_before:
94 ····break_path·=·f"{lock_file}.break.{os.getpid()}.{secrets.token_hex(16)}" 
95 ····Path(lock_file).rename(break_path) 
96 ····try: 
97 ········st_after·=·os.lstat(break_path) 
98 ····except·OSError: 
99 ········return106 ········return
 107 ····break_path:·Final[str]·=·f"{lock_file}.break.{os.getpid()}.{secrets.token_hex(16)}"
 108 ····Path(lock_file).rename(break_path)
100 ····if·st_after.st_mtime·>·mtime_before·or·st_after.st_ino·!=·ino_before:109 ····if·(st_after·:=·os.lstat(break_path)).st_mtime·<=·mtime_before·and·st_after.st_ino·==·ino_before:
101 ········return 
102 ····Path(break_path).unlink()110 ········Path(break_path).unlink()
 111 ····elif·stat.S_ISREG(st_after.st_mode)·and·_HAS_LINK:··#·pragma:·needs·hard-link
 112 ········with·suppress(FileExistsError):
 113 ············os.link(break_path,·lock_file)
 114 ············Path(break_path).unlink()
  
  
103 def·touch(name:·str,·*,·fd:·int·|·None·=·None)·->·None:115 def·touch(name:·str,·*,·fd:·int)·->·None:
104 ····#·Prefer·the·already-open,·already-verified·fd·so·a·peer·that·swaps·a·symlink·or·a·different·file·in·at·the116 ····#·Prefer·the·already-open,·already-verified·fd·so·a·peer·that·swaps·a·symlink·or·a·different·file·in·at·the
105 ····#·path·after·our·O_NOFOLLOW·read·cannot·redirect·the·touch:·utime·then·targets·the·inode·behind·the·fd.117 ····#·path·after·our·O_NOFOLLOW·read·cannot·redirect·the·touch:·utime·then·targets·the·inode·behind·the·fd.
106 ····#·Where·the·platform·cannot·utime·an·fd,·fall·back·to·a·path-based·touch·that·still·refuses·to·follow·a118 ····#·Where·the·platform·cannot·utime·an·fd,·fall·back·to·a·path-based·touch·that·still·refuses·to·follow·a
107 ····#·symlink·where·supported,·matching·the·O_NOFOLLOW·reads·used·elsewhere·here.119 ····#·symlink·where·supported,·matching·the·O_NOFOLLOW·reads·used·elsewhere·here.
108 ····if·fd·is·not·None·and·_SUPPORTS_UTIME_FD:··#·pragma:·needs·utime-fd120 ····if·_SUPPORTS_UTIME_FD:··#·pragma:·needs·utime-fd
109 ········os.utime(fd,·None)121 ········os.utime(fd,·None)
110 ········return122 ········return
111 ····os.utime(name,·None,·follow_symlinks=not·_SUPPORTS_UTIME_NOFOLLOW)123 ····os.utime(name,·None,·follow_symlinks=not·_SUPPORTS_UTIME_NOFOLLOW)··#·pragma:·lacks·utime-fd
  
  
Max diff block lines reached; 307/9104 bytes (3.37%) of diff not shown.
⊟
5.4 KB
filelock/_windows.py
    
Offset 1, 11 lines modifiedOffset 1, 12 lines modified
1 from·__future__·import·annotations1 from·__future__·import·annotations
  
2 import·os2 import·os
3 import·sys3 import·sys
 4 import·time
4 from·contextlib·import·suppress5 from·contextlib·import·suppress
5 from·pathlib·import·Path6 from·pathlib·import·Path
6 from·typing·import·Final,·cast7 from·typing·import·Final,·cast
  
7 from·._api·import·BaseFileLock8 from·._api·import·BaseFileLock
8 from·._util·import·ensure_directory_exists,·raise_on_not_writable_file9 from·._util·import·ensure_directory_exists,·raise_on_not_writable_file
  
Offset 37, 22 lines modifiedOffset 38, 27 lines modified
37 ····#·LockFileEx·locks·a·byte·range·at·an·offset·carried·in·OVERLAPPED,·independent·of·the·descriptor's·file·position.38 ····#·LockFileEx·locks·a·byte·range·at·an·offset·carried·in·OVERLAPPED,·independent·of·the·descriptor's·file·position.
38 ····#·msvcrt.locking·starts·at·the·current·position·instead,·so·a·metadata·write·between·lock·and·unlock·could·shift39 ····#·msvcrt.locking·starts·at·the·current·position·instead,·so·a·metadata·write·between·lock·and·unlock·could·shift
39 ····#·the·byte·a·later·unlock·targets;·the·explicit·offset·removes·that·hazard·for·both·the·path·lock·and·#608's40 ····#·the·byte·a·later·unlock·targets;·the·explicit·offset·removes·that·hazard·for·both·the·path·lock·and·#608's
40 ····#·descriptor·lock.41 ····#·descriptor·lock.
41 ····_LOCKFILE_FAIL_IMMEDIATELY:·Final[int]·=·0x0000000142 ····_LOCKFILE_FAIL_IMMEDIATELY:·Final[int]·=·0x00000001
42 ····_LOCKFILE_EXCLUSIVE_LOCK:·Final[int]·=·0x0000000243 ····_LOCKFILE_EXCLUSIVE_LOCK:·Final[int]·=·0x00000002
43 ····_ERROR_LOCK_VIOLATION:·Final[int]·=·33··#·another·handle·holds·the·byte·range44 ····_ERROR_LOCK_VIOLATION:·Final[int]·=·33··#·another·handle·holds·the·byte·range
 45 ····_ERROR_NOT_LOCKED:·Final[int]·=·158··#·the·byte·range·is·not·locked
  
44 ····#·NtCreateFile·returns·the·raw·NTSTATUS·as·its·value,·where·CreateFileW·collapses·several·of·these·into·one46 ····#·NtCreateFile·returns·the·raw·NTSTATUS·as·its·value,·where·CreateFileW·collapses·several·of·these·into·one
45 ····#·ERROR_ACCESS_DENIED.·Telling·them·apart·is·the·point·(#604):·a·name·pending·deletion·or·a·share·conflict·is47 ····#·ERROR_ACCESS_DENIED.·Telling·them·apart·is·the·point·(#604):·a·name·pending·deletion·or·a·share·conflict·is
46 ····#·transient·and·worth·a·retry,·a·real·access·denial·is·not.48 ····#·transient·and·worth·a·retry,·a·real·access·denial·is·not.
47 ····_STATUS_SUCCESS:·Final[int]·=·0x0000000049 ····_STATUS_SUCCESS:·Final[int]·=·0x00000000
48 ····_STATUS_ACCESS_DENIED:·Final[int]·=·0xC000002250 ····_STATUS_ACCESS_DENIED:·Final[int]·=·0xC0000022
49 ····_STATUS_SHARING_VIOLATION:·Final[int]·=·0xC000004351 ····_STATUS_SHARING_VIOLATION:·Final[int]·=·0xC0000043
50 ····_STATUS_DELETE_PENDING:·Final[int]·=·0xC000005652 ····_STATUS_DELETE_PENDING:·Final[int]·=·0xC0000056
 53 ····#:·How·long·an·open·waits·out·a·STATUS_ACCESS_DENIED·before·treating·it·as·a·real·denial:·NTFS·answers·it·for·a
 54 ····#:·moment·while·a·peer's·unlink·tears·the·name·down,·so·a·bounded·wait·keeps·a·real·denial·failing·fast·(#604).
 55 ····_ACCESS_DENIED_GRACE:·Final[float]·=·0.5
 56 ····_ACCESS_DENIED_RETRY:·Final[float]·=·0.002
  
51 ····_ntdll:·Final[ctypes.WinDLL]·=·ctypes.WinDLL("ntdll")57 ····_ntdll:·Final[ctypes.WinDLL]·=·ctypes.WinDLL("ntdll")
52 ····_kernel32:·Final[ctypes.WinDLL]·=·ctypes.WinDLL("kernel32",·use_last_error=True)58 ····_kernel32:·Final[ctypes.WinDLL]·=·ctypes.WinDLL("kernel32",·use_last_error=True)
  
53 ····class·_UNICODE_STRING(ctypes.Structure):··#·ruff:ignore[invalid-class-name]··#·mirrors·the·Win32·struct·name59 ····class·_UNICODE_STRING(ctypes.Structure):··#·ruff:ignore[invalid-class-name]··#·mirrors·the·Win32·struct·name
54 ········_fields_·=·(60 ········_fields_·=·(
55 ············("Length",·wintypes.USHORT),··#·byte·length,·not·character·count61 ············("Length",·wintypes.USHORT),··#·byte·length,·not·character·count
Offset 159, 17 lines modifiedOffset 165, 19 lines modified
159 ········if·err·==·_ERROR_LOCK_VIOLATION:165 ········if·err·==·_ERROR_LOCK_VIOLATION:
160 ············return·False166 ············return·False
161 ········#·A·non-contention·LockFileEx·failure·is·not·reproducible·in-process.167 ········#·A·non-contention·LockFileEx·failure·is·not·reproducible·in-process.
162 ········raise·ctypes.WinError(err)··#·pragma:·no·cover168 ········raise·ctypes.WinError(err)··#·pragma:·no·cover
  
163 ····def·_unlock_fd(fd:·int)·->·None:169 ····def·_unlock_fd(fd:·int)·->·None:
164 ········overlapped·=·_OVERLAPPED()··#·the·same·offset·0·and·one-byte·length·the·lock·used170 ········overlapped·=·_OVERLAPPED()··#·the·same·offset·0·and·one-byte·length·the·lock·used
165 ········#·Unlocking·the·exact·range·we·hold·does·not·fail.171 ········if·(··#·pragma:·no·cover··#·only·an·interrupted·earlier·release·leaves·our·own·range·unlocked
166 ········if·not·_kernel32.UnlockFileEx(msvcrt.get_osfhandle(fd),·0,·1,·0,·ctypes.byref(overlapped)):··#·pragma:·no·cover172 ············not·_kernel32.UnlockFileEx(msvcrt.get_osfhandle(fd),·0,·1,·0,·ctypes.byref(overlapped))
 173 ············and·(err·:=·ctypes.get_last_error())·!=·_ERROR_NOT_LOCKED
 174 ········):
167 ············raise·ctypes.WinError(ctypes.get_last_error())175 ············raise·ctypes.WinError(err)
  
168 ····class·WindowsFileLock(BaseFileLock):176 ····class·WindowsFileLock(BaseFileLock):
169 ········"""177 ········"""
170 ········Uses·``LockFileEx``·to·hard·lock·a·byte·range·of·the·lock·file·on·Windows·systems.178 ········Uses·``LockFileEx``·to·hard·lock·a·byte·range·of·the·lock·file·on·Windows·systems.
  
171 ········Lock·file·cleanup:·Windows·attempts·to·delete·the·lock·file·after·release,·but·deletion·is179 ········Lock·file·cleanup:·Windows·attempts·to·delete·the·lock·file·after·release,·but·deletion·is
172 ········not·guaranteed·in·multi-threaded·scenarios·where·another·thread·holds·an·open·handle.·The·lock180 ········not·guaranteed·in·multi-threaded·scenarios·where·another·thread·holds·an·open·handle.·The·lock
Offset 231, 20 lines modifiedOffset 239, 27 lines modified
231 ········:param·mode:·the·permission·mode;·as·``os.open``·does·on·Windows,·a·cleared·owner-write·bit·creates·the·file239 ········:param·mode:·the·permission·mode;·as·``os.open``·does·on·Windows,·a·cleared·owner-write·bit·creates·the·file
232 ············read-only.·The·attribute·only·takes·effect·when·the·file·is·created,·not·when·an·existing·one·is·opened.240 ············read-only.·The·attribute·only·takes·effect·when·the·file·is·created,·not·when·an·existing·one·is·opened.
  
233 ········:returns:·a·file·descriptor·owning·the·opened·handle,·or·``None``·on·a·sharing·violation·or·a·delete-pending241 ········:returns:·a·file·descriptor·owning·the·opened·handle,·or·``None``·on·a·sharing·violation·or·a·delete-pending
234 ············name·the·caller·should·treat·as·contention·and·retry.242 ············name·the·caller·should·treat·as·contention·and·retry.
  
235 ········:raises·OSError:·if·the·path·resolves·to·a·reparse·point,·or·the·open·fails·for·any·other·reason,·raised·with243 ········:raises·OSError:·if·the·path·resolves·to·a·reparse·point,·or·the·open·fails·for·any·other·reason,·raised·with
236 ············the·Win32·error·the·status·maps·to.244 ············the·Win32·error·the·status·maps·to.·An·access·denial·is·raised·only·once·it·outlasts·a·short·grace,·since
 245 ············a·peer·unlinking·the·file·as·it·releases·can·make·the·open·answer·``STATUS_ACCESS_DENIED``·for·a·moment.
  
237 ········"""246 ········"""
238 ········#·Emit·the·audit·event·os.open·would,·so·consumers·watching·"open"·still·see·the·path-level·open·and·can·veto.247 ········#·Emit·the·audit·event·os.open·would,·so·consumers·watching·"open"·still·see·the·path-level·open·and·can·veto.
239 ········sys.audit("open",·path,·None,·os.O_RDWR·|·os.O_CREAT)248 ········sys.audit("open",·path,·None,·os.O_RDWR·|·os.O_CREAT)
 249 ········read_only·=·not·mode·&·_OWNER_WRITE
240 ········handle,·status·=·_nt_open(path,·read_only=not·mode·&·_OWNER_WRITE)250 ········handle,·status·=·_nt_open(path,·read_only=read_only)
 251 ········if·status·==·_STATUS_ACCESS_DENIED:
 252 ············deadline·=·time.monotonic()·+·_ACCESS_DENIED_GRACE
 253 ············while·status·==·_STATUS_ACCESS_DENIED·and·time.monotonic()·<·deadline:
 254 ················time.sleep(_ACCESS_DENIED_RETRY)
 255 ················handle,·status·=·_nt_open(path,·read_only=read_only)
241 ········if·status·!=·_STATUS_SUCCESS:256 ········if·status·!=·_STATUS_SUCCESS:
242 ············if·status·in·{_STATUS_SHARING_VIOLATION,·_STATUS_DELETE_PENDING}:257 ············if·status·in·{_STATUS_SHARING_VIOLATION,·_STATUS_DELETE_PENDING}:
243 ················return·None258 ················return·None
244 ············winerror·=·_ntdll.RtlNtStatusToDosError(status)259 ············winerror·=·_ntdll.RtlNtStatusToDosError(status)
245 ············raise·OSError(None,·ctypes.FormatError(winerror).strip(),·path,·winerror)260 ············raise·OSError(None,·ctypes.FormatError(winerror).strip(),·path,·winerror)
  
246 ········info·=·_BY_HANDLE_FILE_INFORMATION()261 ········info·=·_BY_HANDLE_FILE_INFORMATION()
Offset 316, 8 lines modifiedOffset 331, 9 lines modified
  
316 ········def·_release(self)·->·None:331 ········def·_release(self)·->·None:
317 ············raise·NotImplementedError332 ············raise·NotImplementedError
  
  
318 __all__·=·[333 __all__·=·[
319 ····"WindowsFileLock",334 ····"WindowsFileLock",
 335 ····"_open_non_reparse_fd",
320 ]336 ]
⊟
23.7 KB
filelock/asyncio.py
    
Offset 1, 75 lines modifiedOffset 1, 79 lines modified
1 """An·asyncio-based·implementation·of·the·file·lock."""1 """An·asyncio-based·implementation·of·the·file·lock."""
  
2 from·__future__·import·annotations2 from·__future__·import·annotations
  
3 import·asyncio3 import·asyncio
4 import·contextlib4 import·contextlib
 5 import·functools
5 import·logging6 import·logging
6 import·os7 import·os
 8 import·sys
7 import·time9 import·time
 10 from·concurrent·import·futures
8 from·dataclasses·import·dataclass11 from·dataclasses·import·dataclass,·fields
9 from·inspect·import·iscoroutinefunction12 from·inspect·import·iscoroutinefunction
10 from·threading·import·local13 from·threading·import·RLock
11 from·typing·import·TYPE_CHECKING,·Final,·NoReturn,·TypeVar,·cast14 from·typing·import·TYPE_CHECKING,·Final,·NoReturn,·TypeVar,·cast
  
12 from·._api·import·(15 from·._api·import·(
13 ····_UNSET_FILE_MODE,16 ····_UNSET_FILE_MODE,
14 ····BaseFileLock,17 ····BaseFileLock,
15 ····CloseErrorPolicy,18 ····CloseErrorPolicy,
16 ····ContextErrorPolicy,19 ····ContextErrorPolicy,
17 ····FileLockContext,20 ····FileLockContext,
18 ····FileLockMeta,21 ····FileLockMeta,
 22 ····ThreadLocalFileContext,
19 ····_append_exception_context,23 ····_append_exception_context,
20 ····_canonical,24 ····_canonical,
 25 ····_delegate_to_current,
21 ····_ExtraValue,26 ····_ExtraValue,
22 ····_fork_transition,27 ····_fork_transition,
23 ····_grouped_errors,28 ····_grouped_errors,
24 ····_raise_body_and_release,29 ····_raise_body_and_release,
25 ····_raise_chained_errors,30 ····_raise_chained_errors,
26 ····_raise_cleanup_errors,31 ····_raise_cleanup_errors,
27 ····_raise_grouped_errors,32 ····_raise_grouped_errors,
28 ····_register_fork_object,33 ····_register_fork_object,
 34 ····_resolve_poll_interval,
 35 ····_resolve_timeout,
29 )36 )
30 from·._async·import·(37 from·._async·import·(
31 ····_AsyncTransitionGate,38 ····_AsyncTransitionGate,
32 ····_AsyncTransitionUnavailableError,39 ····_AsyncTransitionUnavailableError,
33 ····_BackendOutcome,40 ····_BackendOutcome,
34 ····_capture_awaitable,41 ····_capture_awaitable,
35 ····_capture_call,42 ····_capture_call,
36 ····_drain_future,43 ····_drain_future,
37 ····_future_result,44 ····_future_result,
 45 ····_run_in_executor,
38 ····_wait_until_done,46 ····_wait_until_done,
39 )47 )
40 from·._error·import·Timeout48 from·._error·import·Timeout
41 from·._lease·import·SoftFileLease49 from·._lease·import·SoftFileLease
42 from·._soft·import·SoftFileLock50 from·._soft·import·SoftFileLock
43 from·._strict·import·StrictSoftFileLock51 from·._strict·import·StrictSoftFileLock
44 from·._unix·import·UnixFileLock52 from·._unix·import·UnixFileLock
45 from·._windows·import·WindowsFileLock53 from·._windows·import·WindowsFileLock
  
46 if·TYPE_CHECKING:54 if·TYPE_CHECKING:
47 ····import·sys 
48 ····from·collections.abc·import·Awaitable,·Callable,·Coroutine,·Hashable55 ····from·collections.abc·import·Awaitable,·Callable,·Coroutine,·Hashable,·Mapping
49 ····from·concurrent·import·futures 
50 ····from·types·import·TracebackType56 ····from·types·import·TracebackType
  
51 ····if·sys.version_info·>=·(3,·11):··#·pragma:·no·cover·(py311+) 
52 ········from·typing·import·Self57 ····from·typing·import·Self
53 ····else:··#·pragma:·no·cover·(<py311) 
54 ········from·typing_extensions·import·Self 
  
  
55 _LOGGER:·Final[logging.Logger]·=·logging.getLogger("filelock")58 _LOGGER:·Final[logging.Logger]·=·logging.getLogger("filelock")
56 _ASYNC_RELEASE_CANCELLATION_ERRORS:·Final[str]·=·"lock·release·cancellation·and·backend·release·both·failed"59 _ASYNC_RELEASE_CANCELLATION_ERRORS:·Final[str]·=·"lock·release·cancellation·and·backend·release·both·failed"
57 _ASYNC_CONTEXT_RELEASE_ERRORS:·Final[str]·=·"context·body,·release·cancellation,·and·backend·release·failed"60 _ASYNC_CONTEXT_RELEASE_ERRORS:·Final[str]·=·"context·body,·release·cancellation,·and·backend·release·failed"
58 _ASYNC_RELEASE_CANCELLATION_MARKER_ATTR:·Final[str]·=·"_filelock_async_release_cancellation"61 _ASYNC_RELEASE_CANCELLATION_MARKER_ATTR:·Final[str]·=·"_filelock_async_release_cancellation"
59 _ASYNC_RELEASE_CANCELLATION_MARKER:·Final[list[None]]·=·[]62 _ASYNC_RELEASE_CANCELLATION_MARKER:·Final[list[None]]·=·[]
 63 _FINALIZER_RELEASES:·Final[set[asyncio.Task[None]·|·futures.Future[None]]]·=·set()
  
60 _AT·=·TypeVar("_AT",·bound="BaseAsyncFileLock")64 _AT·=·TypeVar("_AT",·bound="BaseAsyncFileLock")
 65 _T·=·TypeVar("_T")
  
  
61 class·AsyncFileLockMeta(FileLockMeta):66 class·AsyncFileLockMeta(FileLockMeta):
62 ····def·__call__(··#·ruff:ignore[too-many-arguments]··#·forwards·the·public·constructor's·documented·parameters67 ····def·__call__(··#·ruff:ignore[too-many-arguments]··#·forwards·the·public·constructor's·documented·parameters
63 ········cls:·type[_AT],··#·ruff:ignore[invalid-first-argument-name-for-method]··#·metaclass·__call__·receives·the·class·being·constructed68 ········cls:·type[_AT],··#·ruff:ignore[invalid-first-argument-name-for-method]··#·metaclass·__call__·receives·the·class·being·constructed
64 ········lock_file:·str·|·os.PathLike[str],69 ········lock_file:·str·|·os.PathLike[str],
65 ········timeout:·float·=·-1,70 ········timeout:·float·=·-1,
Offset 159, 20 lines modifiedOffset 163, 20 lines modified
159 ········:param·lock_file:·path·to·the·file163 ········:param·lock_file:·path·to·the·file
160 ········:param·timeout:·default·timeout·when·acquiring·the·lock,·in·seconds.·It·will·be·used·as·fallback·value·in·the164 ········:param·timeout:·default·timeout·when·acquiring·the·lock,·in·seconds.·It·will·be·used·as·fallback·value·in·the
161 ············acquire·method,·if·no·timeout·value·(``None``)·is·given.·If·you·want·to·disable·the·timeout,·set·it·to·a165 ············acquire·method,·if·no·timeout·value·(``None``)·is·given.·If·you·want·to·disable·the·timeout,·set·it·to·a
162 ············negative·value.·A·timeout·of·0·means·that·there·is·exactly·one·attempt·to·acquire·the·file·lock.166 ············negative·value.·A·timeout·of·0·means·that·there·is·exactly·one·attempt·to·acquire·the·file·lock.
163 ········:param·mode:·file·permissions·for·the·lockfile.·When·not·specified,·the·OS·controls·permissions·via·umask·and167 ········:param·mode:·file·permissions·for·the·lockfile.·When·not·specified,·the·OS·controls·permissions·via·umask·and
164 ············default·ACLs,·preserving·POSIX·default·ACL·inheritance·in·shared·directories.168 ············default·ACLs,·preserving·POSIX·default·ACL·inheritance·in·shared·directories.
165 ········:param·thread_local:·Whether·this·object's·internal·context·should·be·thread·local·or·not.·If·this·is·set·to169 ········:param·thread_local:·Whether·this·object's·internal·context·should·be·thread·local·or·not.·If·this·is·set·to
166 ············``False``·then·the·lock·will·be·reentrant·across·threads.·When·``True``·(the·default),·**all·fields·of·the170 ············``False``·(the·default)·then·the·lock·will·be·reentrant·across·threads.·When·``True``,·**all·fields·of·the
167 ············lock's·internal·context·are·per-thread**,·including·the·configuration·values·``poll_interval``,·``timeout``,171 ············lock's·internal·context·are·per-thread**,·including·the·configuration·values·``poll_interval``,·``timeout``,
168 ············``blocking``,·``mode``,·and·``lifetime``.·Setting·one·of·these·properties·from·one·thread·does·not·change172 ············``blocking``,·``mode``,·and·``lifetime``.·Setting·one·of·these·properties·from·one·thread·does·not·change
169 ············the·value·seen·by·another·thread;·threads·that·did·not·perform·the·write·continue·to·see·the·value·supplied173 ············the·value·seen·by·another·thread;·threads·that·did·not·perform·the·write·continue·to·see·the·value·supplied
170 ············at·construction·time.·If·you·need·configuration·values·to·be·visible·across·threads,·construct·the·lock 
171 ············with·``thread_local=False``.174 ············at·construction·time.·``mode``·has·no·setter,·so·construction·is·the·only·place·it·is·ever·set.·If·you·need
 175 ············configuration·values·to·be·visible·across·threads,·construct·the·lock·with·``thread_local=False``.
172 ········:param·blocking:·whether·the·lock·should·be·blocking·or·not176 ········:param·blocking:·whether·the·lock·should·be·blocking·or·not
173 ········:param·is_singleton:·If·this·is·set·to·``True``·then·only·one·instance·of·this·class·will·be·created·per·lock177 ········:param·is_singleton:·If·this·is·set·to·``True``·then·only·one·instance·of·this·class·will·be·created·per·lock
174 ············file.·This·is·useful·if·you·want·to·use·the·lock·object·for·reentrant·locking·without·needing·to·pass·the178 ············file.·This·is·useful·if·you·want·to·use·the·lock·object·for·reentrant·locking·without·needing·to·pass·the
175 ············same·object·around.179 ············same·object·around.
176 ········:param·poll_interval:·default·interval·for·polling·the·lock·file,·in·seconds.·It·will·be·used·as·fallback·value180 ········:param·poll_interval:·default·interval·for·polling·the·lock·file,·in·seconds.·It·will·be·used·as·fallback·value
177 ············in·the·acquire·method,·if·no·poll_interval·value·(``None``)·is·given.181 ············in·the·acquire·method,·if·no·poll_interval·value·(``None``)·is·given.
178 ········:param·lifetime:·for·:class:`AsyncSoftFileLock`,·the·age·in·seconds·after·which·a·waiting·process·may·delete182 ········:param·lifetime:·for·:class:`AsyncSoftFileLock`,·the·age·in·seconds·after·which·a·waiting·process·may·delete
Offset 193, 42 lines modifiedOffset 197, 60 lines modified
193 ············identity·(Windows·skips·its·unlink,·Unix·refuses·the·``ENOSYS``·soft·fallback).·:class:`AsyncSoftFileLock`197 ············identity·(Windows·skips·its·unlink,·Unix·refuses·the·``ENOSYS``·soft·fallback).·:class:`AsyncSoftFileLock`
194 ············rejects·``True``.198 ············rejects·``True``.
195 ········:param·on_acquired:·for·native·locks·(:class:`AsyncFileLock`),·a·callable·invoked·with·the·borrowed·lock199 ········:param·on_acquired:·for·native·locks·(:class:`AsyncFileLock`),·a·callable·invoked·with·the·borrowed·lock
196 ············descriptor·once·per·physical·acquisition,·after·the·lock·is·held·but·before200 ············descriptor·once·per·physical·acquisition,·after·the·lock·is·held·but·before
197 ············:meth:`~BaseAsyncFileLock.acquire`·returns.·With·``run_in_executor=True``·(the·default)·it·runs·in·the201 ············:meth:`~BaseAsyncFileLock.acquire`·returns.·With·``run_in_executor=True``·(the·default)·it·runs·in·the
198 ············backend·executor.·It·must·not·close·or·unlock·the·descriptor;·a·raise·rolls·the·acquisition·back.202 ············backend·executor.·It·must·not·close·or·unlock·the·descriptor;·a·raise·rolls·the·acquisition·back.
199 ············:class:`AsyncSoftFileLock`·rejects·it.203 ············:class:`AsyncSoftFileLock`·rejects·it.
200 ········:param·loop:·The·event·loop·to·use.·If·not·specified,·the·running·event·loop·will·be·used.204 ········:param·loop:·the·event·loop·a·garbage-collected·lock·schedules·its·release·on·when·no·loop·runs·in·the
 205 ············collecting·thread.·:meth:`~BaseAsyncFileLock.acquire`·and·:meth:`~BaseAsyncFileLock.release`·always·run
 206 ············on·the·loop·that·awaits·them.
201 ········:param·run_in_executor:·If·this·is·set·to·``True``·then·the·lock·will·be·acquired·in·an·executor.207 ········:param·run_in_executor:·If·this·is·set·to·``True``·then·the·lock·will·be·acquired·in·an·executor.
202 ········:param·executor:·The·executor·to·use.·If·not·specified,·the·default·executor·will·be·used.208 ········:param·executor:·The·executor·to·use.·If·not·specified,·the·default·executor·will·be·used.
  
203 ········"""209 ········"""
204 ········self._creator_pid·=·os.getpid()210 ········self._creator_pid·=·os.getpid()
205 ········self._is_thread_local·=·thread_local211 ········self._is_thread_local·=·thread_local
206 ········self._is_singleton·=·is_singleton212 ········self._is_singleton·=·is_singleton
207 ········self._context_error_policy·=·context_error_policy··#·already·validated·by·the·metaclass213 ········self._context_error_policy·=·context_error_policy··#·already·validated·by·the·metaclass
208 ········self._close_error_policy·=·close_error_policy··#·already·validated·by·the·metaclass214 ········self._close_error_policy·=·close_error_policy··#·already·validated·by·the·metaclass
Max diff block lines reached; 17305/24240 bytes (71.39%) of diff not shown.
⊟
420 B
filelock/version.py
    
Offset 14, 11 lines modifiedOffset 14, 11 lines modified
14 version:·str14 version:·str
15 __version__:·str15 __version__:·str
16 __version_tuple__:·tuple[int·|·str,·...]16 __version_tuple__:·tuple[int·|·str,·...]
17 version_tuple:·tuple[int·|·str,·...]17 version_tuple:·tuple[int·|·str,·...]
18 commit_id:·str·|·None18 commit_id:·str·|·None
19 __commit_id__:·str·|·None19 __commit_id__:·str·|·None
  
20 __version__·=·version·=·'3.32.0'20 __version__·=·version·=·'4.1.1'
21 __version_tuple__·=·version_tuple·=·(3,·32,·0)21 __version_tuple__·=·version_tuple·=·(4,·1,·1)
  
22 __commit_id__·=·commit_id·=·None22 __commit_id__·=·commit_id·=·None
⊟
452 B
filelock/_soft_rw/__init__.py
    
Offset 1, 8 lines modifiedOffset 1, 8 lines modified
1 """Cross-process·and·cross-host·reader/writer·lock·on·:class:`~filelock.SoftFileLock`·primitives."""1 """Cross-process·and·cross-host·reader/writer·lock·over·a·generation·log·of·immutable·snapshots."""
  
2 from·__future__·import·annotations2 from·__future__·import·annotations
  
3 from·._async·import·AsyncAcquireSoftReadWriteReturnProxy,·AsyncSoftReadWriteLock3 from·._async·import·AsyncAcquireSoftReadWriteReturnProxy,·AsyncSoftReadWriteLock
4 from·._sync·import·SoftReadWriteLock4 from·._sync·import·SoftReadWriteLock
  
5 __all__·=·[5 __all__·=·[
⊟
14.9 KB
filelock/_soft_rw/_async.py
    
Offset 2, 42 lines modifiedOffset 2, 60 lines modified
  
2 from·__future__·import·annotations2 from·__future__·import·annotations
  
3 import·asyncio3 import·asyncio
4 import·functools4 import·functools
5 import·os5 import·os
6 from·contextlib·import·asynccontextmanager6 from·contextlib·import·asynccontextmanager
7 from·typing·import·TYPE_CHECKING,·ParamSpec,·TypeVar7 from·typing·import·TYPE_CHECKING,·Literal,·ParamSpec,·TypeVar
  
 8 from·filelock._async·import·(
 9 ····_BackendOutcome,
 10 ····_capture_call,
 11 ····_drain_future,
 12 ····_future_result,
 13 ····_raise_cancelled_error,
 14 ····_task_owners_for,
 15 ····_wait_until_done,
 16 )
  
8 from·._sync·import·SoftReadWriteLock17 from·._sync·import·SoftReadWriteLock
  
9 if·TYPE_CHECKING:18 if·TYPE_CHECKING:
10 ····from·collections.abc·import·AsyncGenerator,·Callable19 ····from·collections.abc·import·AsyncGenerator,·Callable
11 ····from·concurrent·import·futures20 ····from·concurrent·import·futures
12 ····from·types·import·TracebackType21 ····from·types·import·TracebackType
  
 22 ····from·filelock._api·import·AcquireReturnProxy
 23 ····from·filelock._lease·import·LeaseCompromise
  
13 _P·=·ParamSpec("_P")24 _P·=·ParamSpec("_P")
14 _R·=·TypeVar("_R")25 _R·=·TypeVar("_R")
  
  
15 class·AsyncSoftReadWriteLock:26 class·AsyncSoftReadWriteLock:
16 ····"""27 ····"""
17 ····Async·wrapper·around·:class:`SoftReadWriteLock`·for·``asyncio``·applications.28 ····Async·wrapper·around·:class:`SoftReadWriteLock`·for·``asyncio``·applications.
  
18 ····The·sync·class's·blocking·filesystem·operations·run·on·a·thread·pool·via·``loop.run_in_executor()``.·The29 ····The·sync·class's·blocking·filesystem·operations·run·on·a·thread·pool·via·``loop.run_in_executor()``.·Each
19 ····underlying·:class:`SoftReadWriteLock`·handles·reentrancy,·upgrade/downgrade·rules,·fork·handling,·heartbeat·and 
20 ····TTL·stale·detection,·and·singleton·behavior.30 ····``asyncio``·task·owns·its·own·hold.·Tasks·share·a·read·lock,·and·a·task·asking·for·the·write·lock·waits·until·the
 31 ····other·holders·release,·with·waiting·writers·ahead·of·new·readers.·Upgrading·or·downgrading·a·held·lock·raises
 32 ····:class:`RuntimeError`.·The·underlying·:class:`SoftReadWriteLock`·handles·forks,·the·heartbeat,·and·stale·eviction.
 33 ····Singleton·wrappers·share·one·sync·lock·and·its·task·holds.
  
21 ····:param·lock_file:·path·to·the·lock·file;·sidecar·state/write/readers·live·next·to·it34 ····:param·lock_file:·path·to·the·lock·file;·the·protocol·directory·lives·next·to·it·as·``<lock_file>.rw``
22 ····:param·timeout:·maximum·wait·time·in·seconds;·``-1``·means·block·indefinitely35 ····:param·timeout:·maximum·wait·time·in·seconds;·``-1``·means·block·indefinitely
23 ····:param·blocking:·if·``False``,·raise·:class:`~filelock.Timeout`·immediately·on·contention36 ····:param·blocking:·if·``False``,·raise·:class:`~filelock.Timeout`·immediately·on·contention
24 ····:param·is_singleton:·if·``True``,·reuse·existing·:class:`SoftReadWriteLock`·instances·per·resolved·path37 ····:param·is_singleton:·if·``True``,·reuse·existing·:class:`SoftReadWriteLock`·instances·per·resolved·path
25 ····:param·heartbeat_interval:·seconds·between·heartbeat·refreshes;·default·30·s38 ····:param·heartbeat_interval:·seconds·between·heartbeat·refreshes;·default·30·s
26 ····:param·stale_threshold:·seconds·of·mtime·inactivity·before·a·marker·is·stale;·defaults·to·``3·*·heartbeat_interval``39 ····:param·stale_threshold:·seconds·a·holder·record·may·stay·unchanged·before·a·contender·evicts·it;·defaults·to
 40 ········``3·*·heartbeat_interval``
27 ····:param·poll_interval:·seconds·between·acquire·retries·under·contention;·default·0.25·s41 ····:param·poll_interval:·seconds·between·acquire·retries·under·contention;·default·0.25·s
 42 ····:param·on_compromise:·called·from·the·heartbeat·thread·with·a·:class:`~filelock.LeaseCompromise`·when·the·hold·is
 43 ········lost
28 ····:param·loop:·event·loop·for·``run_in_executor``;·``None``·uses·the·running·loop44 ····:param·loop:·event·loop·for·``run_in_executor``;·``None``·uses·the·running·loop
29 ····:param·executor:·executor·for·``run_in_executor``;·``None``·uses·the·default·executor45 ····:param·executor:·executor·for·``run_in_executor``;·``None``·uses·the·default·executor
  
30 ····..·versionadded::·3.27.046 ····..·versionadded::·3.27.0
  
31 ····"""47 ····"""
  
Offset 47, 27 lines modifiedOffset 65, 30 lines modified
47 ········timeout:·float·=·-1,65 ········timeout:·float·=·-1,
48 ········*,66 ········*,
49 ········blocking:·bool·=·True,67 ········blocking:·bool·=·True,
50 ········is_singleton:·bool·=·True,68 ········is_singleton:·bool·=·True,
51 ········heartbeat_interval:·float·=·30.0,69 ········heartbeat_interval:·float·=·30.0,
52 ········stale_threshold:·float·|·None·=·None,70 ········stale_threshold:·float·|·None·=·None,
53 ········poll_interval:·float·=·0.25,71 ········poll_interval:·float·=·0.25,
 72 ········on_compromise:·Callable[[LeaseCompromise],·None]·|·None·=·None,
54 ········loop:·asyncio.AbstractEventLoop·|·None·=·None,73 ········loop:·asyncio.AbstractEventLoop·|·None·=·None,
55 ········executor:·futures.Executor·|·None·=·None,74 ········executor:·futures.Executor·|·None·=·None,
56 ····)·->·None:75 ····)·->·None:
57 ········self._creator_pid·=·os.getpid()76 ········self._creator_pid·=·os.getpid()
58 ········self._lock·=·SoftReadWriteLock(77 ········self._lock·=·SoftReadWriteLock(
59 ············lock_file,78 ············lock_file,
60 ············timeout,79 ············timeout,
61 ············blocking=blocking,80 ············blocking=blocking,
62 ············is_singleton=is_singleton,81 ············is_singleton=is_singleton,
63 ············heartbeat_interval=heartbeat_interval,82 ············heartbeat_interval=heartbeat_interval,
64 ············stale_threshold=stale_threshold,83 ············stale_threshold=stale_threshold,
65 ············poll_interval=poll_interval,84 ············poll_interval=poll_interval,
 85 ············on_compromise=on_compromise,
66 ········)86 ········)
 87 ········self._owners·=·_task_owners_for(self._lock)
67 ········self._loop·=·loop88 ········self._loop·=·loop
68 ········self._executor·=·executor89 ········self._executor·=·executor
  
69 ····@property90 ····@property
70 ····def·lock_file(self)·->·str:91 ····def·lock_file(self)·->·str:
71 ········"""The·path·to·the·lock·file·passed·to·the·constructor."""92 ········"""The·path·to·the·lock·file·passed·to·the·constructor."""
72 ········return·self._lock.lock_file93 ········return·self._lock.lock_file
Offset 79, 14 lines modifiedOffset 100, 24 lines modified
  
79 ····@property100 ····@property
80 ····def·blocking(self)·->·bool:101 ····def·blocking(self)·->·bool:
81 ········"""Whether·``acquire_*``·defaults·to·blocking;·``False``·makes·contention·raise·immediately."""102 ········"""Whether·``acquire_*``·defaults·to·blocking;·``False``·makes·contention·raise·immediately."""
82 ········return·self._lock.blocking103 ········return·self._lock.blocking
  
83 ····@property104 ····@property
 105 ····def·generation(self)·->·int·|·None:
 106 ········"""The·generation·the·current·hold·was·granted·at,·a·fencing·token;·``None``·when·no·lock·is·held."""
 107 ········return·self._lock.generation
  
 108 ····@property
 109 ····def·compromise(self)·->·LeaseCompromise·|·None:
 110 ········"""How·the·current·hold·was·lost,·or·``None``·while·it·stands."""
 111 ········return·self._lock.compromise
  
 112 ····@property
84 ····def·loop(self)·->·asyncio.AbstractEventLoop·|·None:113 ····def·loop(self)·->·asyncio.AbstractEventLoop·|·None:
85 ········"""The·event·loop·used·for·``run_in_executor``,·or·``None``·for·the·running·loop."""114 ········"""The·event·loop·used·for·``run_in_executor``,·or·``None``·for·the·running·loop."""
86 ········return·self._loop115 ········return·self._loop
  
87 ····@property116 ····@property
88 ····def·executor(self)·->·futures.Executor·|·None:117 ····def·executor(self)·->·futures.Executor·|·None:
89 ········"""The·executor·used·for·``run_in_executor``,·or·``None``·for·the·default·executor."""118 ········"""The·executor·used·for·``run_in_executor``,·or·``None``·for·the·default·executor."""
Offset 96, 16 lines modifiedOffset 127, 18 lines modified
96 ····async·def·read_lock(self,·timeout:·float·|·None·=·None,·*,·blocking:·bool·|·None·=·None)·->·AsyncGenerator[None]:127 ····async·def·read_lock(self,·timeout:·float·|·None·=·None,·*,·blocking:·bool·|·None·=·None)·->·AsyncGenerator[None]:
97 ········"""128 ········"""
98 ········Async·context·manager·that·acquires·and·releases·a·shared·read·lock.129 ········Async·context·manager·that·acquires·and·releases·a·shared·read·lock.
  
99 ········:param·timeout:·maximum·wait·time·in·seconds,·or·``None``·to·use·the·instance·default130 ········:param·timeout:·maximum·wait·time·in·seconds,·or·``None``·to·use·the·instance·default
100 ········:param·blocking:·if·``False``,·raise·:class:`~filelock.Timeout`·immediately;·``None``·uses·the·instance·default131 ········:param·blocking:·if·``False``,·raise·:class:`~filelock.Timeout`·immediately;·``None``·uses·the·instance·default
  
101 ········:raises·RuntimeError:·if·a·write·lock·is·already·held·on·this·instance132 ········:raises·RuntimeError:·if·the·calling·task·already·holds·the·write·lock
102 ········:raises·Timeout:·if·the·lock·cannot·be·acquired·within·*timeout*·seconds133 ········:raises·Timeout:·if·the·lock·cannot·be·acquired·within·*timeout*·seconds
Max diff block lines reached; 9263/15244 bytes (60.76%) of diff not shown.
⊟
59.5 KB
filelock/_soft_rw/_sync.py
    
Offset 1, 88 lines modifiedOffset 1, 82 lines modified
1 """Cross-process·and·cross-host·reader/writer·lock·built·on·:class:`SoftFileLock`·primitives."""1 """Cross-process·and·cross-host·reader/writer·lock·over·a·generation·log·of·immutable·snapshots."""
  
2 from·__future__·import·annotations2 from·__future__·import·annotations
  
3 import·atexit3 import·atexit
4 import·hmac 
5 import·os4 import·os
6 import·re 
7 import·secrets 
8 import·socket 
9 import·stat 
10 import·sys 
11 import·threading5 import·threading
12 import·time6 import·time
13 import·uuid 
14 from·contextlib·import·closing,·contextmanager,·suppress7 from·contextlib·import·contextmanager,·suppress
15 from·dataclasses·import·dataclass8 from·dataclasses·import·dataclass
16 from·pathlib·import·Path9 from·math·import·isfinite
17 from·typing·import·TYPE_CHECKING,·Final,·Literal10 from·typing·import·TYPE_CHECKING,·Final
18 from·weakref·import·WeakValueDictionary11 from·weakref·import·WeakValueDictionary
  
19 from·filelock._api·import·(12 from·filelock._api·import·(
20 ····AcquireReturnProxy,13 ····AcquireReturnProxy,
 14 ····_canonical,
 15 ····_check_timeout_max,
21 ····_ensure_current_process,16 ····_ensure_current_process,
22 ····_fork_transition, 
23 ····_raise_grouped_errors, 
24 ····_register_fork_class,17 ····_register_fork_class,
25 ····_register_fork_object,18 ····_register_fork_object,
26 ····_register_owned_descriptor, 
27 ····_unregister_owned_descriptor,19 ····_resolve_read_write_timeout,
 20 ····_seconds,
 21 ····_timeout_behavior,
28 )22 )
29 from·filelock._error·import·Timeout23 from·filelock._error·import·Timeout
30 from·filelock._soft·import·SoftFileLock 
31 from·filelock._util·import·ensure_directory_exists,·touch,·write_all24 from·filelock._lease·import·LeaseCompromise
  
 25 from·._protocol·import·GenerationLog,·Ledger,·Mode,·Participant
 26 from·._storage·import·OsFiles
  
32 if·TYPE_CHECKING:27 if·TYPE_CHECKING:
33 ····from·collections.abc·import·Callable,·Generator28 ····from·collections.abc·import·Callable,·Generator
  
 29 ····from·filelock._lease·import·CompromiseReason
  
34 _Mode·=·Literal["read",·"write"] 
35 _BREAK_SUFFIX:·Final[str]·=·".break" 
36 _MAX_MARKER_SIZE:·Final[int]·=·1024 
37 _O_NOFOLLOW:·Final[int]·=·getattr(os,·"O_NOFOLLOW",·0) 
38 _O_NONBLOCK:·Final[int]·=·getattr(os,·"O_NONBLOCK",·0) 
39 #·dirfd-relative·I/O·is·a·Unix-only·optimization;·Windows·cannot·``os.open()``·a·directory·at·all,·and 
40 #·its·``os``·module·skips·dir_fd·support·entirely.·When·disabled,·callers·fall·back·to·full-path·ops. 
41 _SUPPORTS_DIR_FD:·Final[bool]·=·sys.platform·!=·"win32"·and·os.open·in·os.supports_dir_fd 
  
42 _ALL_INSTANCES:·Final[WeakValueDictionary[int,·SoftReadWriteLock]]·=·WeakValueDictionary()30 _ALL_INSTANCES:·Final[WeakValueDictionary[int,·SoftReadWriteLock]]·=·WeakValueDictionary()
43 _ALL_INSTANCES_LOCK:·threading.Lock·=·threading.Lock()31 _ALL_INSTANCES_LOCK:·threading.Lock·=·threading.Lock()
44 _SINGLETONS_UNDER_CONSTRUCTION:·Final[set[Path]]·=·set()32 _SINGLETONS_UNDER_CONSTRUCTION:·Final[set[str]]·=·set()
  
  
45 class·_SoftRWMeta(type):33 class·_SoftRWMeta(type):
46 ····_instances:·WeakValueDictionary[Path,·SoftReadWriteLock]34 ····_instances:·WeakValueDictionary[str,·SoftReadWriteLock]
47 ····_instances_lock:·threading.RLock35 ····_instances_lock:·threading.RLock
  
48 ····def·__call__(··#·ruff:ignore[too-many-arguments]··#·forwards·the·public·constructor's·documented·parameters36 ····def·__call__(··#·ruff:ignore[too-many-arguments]··#·forwards·the·public·constructor's·documented·parameters
49 ········cls,37 ········cls,
50 ········lock_file:·str·|·os.PathLike[str],38 ········lock_file:·str·|·os.PathLike[str],
51 ········timeout:·float·=·-1,39 ········timeout:·float·=·-1,
52 ········*,40 ········*,
53 ········blocking:·bool·=·True,41 ········blocking:·bool·=·True,
54 ········is_singleton:·bool·=·True,42 ········is_singleton:·bool·=·True,
55 ········heartbeat_interval:·float·=·30.0,43 ········heartbeat_interval:·float·=·30.0,
56 ········stale_threshold:·float·|·None·=·None,44 ········stale_threshold:·float·|·None·=·None,
57 ········poll_interval:·float·=·0.25,45 ········poll_interval:·float·=·0.25,
 46 ········on_compromise:·Callable[[LeaseCompromise],·None]·|·None·=·None,
58 ····)·->·SoftReadWriteLock:47 ····)·->·SoftReadWriteLock:
59 ········_ensure_current_process()48 ········_ensure_current_process()
 49 ········timeout·=·_seconds("timeout",·timeout)
 50 ········#·Passed·through·only·when·set,·so·a·subclass·that·declares·its·own·constructor·without·it·keeps·working.
 51 ········extra·=·{}·if·on_compromise·is·None·else·{"on_compromise":·on_compromise}
60 ········if·not·is_singleton:52 ········if·not·is_singleton:
61 ············return·super().__call__(53 ············return·super().__call__(
62 ················lock_file,54 ················lock_file,
63 ················timeout,55 ················timeout,
64 ················blocking=blocking,56 ················blocking=blocking,
65 ················is_singleton=is_singleton,57 ················is_singleton=is_singleton,
66 ················heartbeat_interval=heartbeat_interval,58 ················heartbeat_interval=heartbeat_interval,
67 ················stale_threshold=stale_threshold,59 ················stale_threshold=stale_threshold,
68 ················poll_interval=poll_interval,60 ················poll_interval=poll_interval,
 61 ················**extra,
69 ············)62 ············)
  
 63 ········#·Keyed·like·the·log·root,·so·one·instance·never·spans·two·logs.
70 ········normalized·=·Path(lock_file).resolve()64 ········normalized·=·_canonical(lock_file)
71 ········with·cls._instances_lock:65 ········with·cls._instances_lock:
72 ············instance·=·cls._instances.get(normalized)66 ············instance·=·cls._instances.get(normalized)
73 ············if·instance·is·None:67 ············if·instance·is·None:
74 ················if·normalized·in·_SINGLETONS_UNDER_CONSTRUCTION:··#·pragma:·needs·fork68 ················if·normalized·in·_SINGLETONS_UNDER_CONSTRUCTION:··#·pragma:·needs·fork
75 ····················msg·=·f"Singleton·lock·construction·is·already·active·for·{lock_file!s}"69 ····················msg·=·f"Singleton·lock·construction·is·already·active·for·{lock_file!s}"
76 ····················raise·RuntimeError(msg)70 ····················raise·RuntimeError(msg)
77 ················construction_pid·=·os.getpid()71 ················construction_pid·=·os.getpid()
Offset 92, 150 lines modifiedOffset 86, 190 lines modified
92 ························lock_file,86 ························lock_file,
93 ························timeout,87 ························timeout,
94 ························blocking=blocking,88 ························blocking=blocking,
95 ························is_singleton=is_singleton,89 ························is_singleton=is_singleton,
96 ························heartbeat_interval=heartbeat_interval,90 ························heartbeat_interval=heartbeat_interval,
97 ························stale_threshold=stale_threshold,91 ························stale_threshold=stale_threshold,
98 ························poll_interval=poll_interval,92 ························poll_interval=poll_interval,
 93 ························**extra,
99 ····················)94 ····················)
100 ················finally:95 ················finally:
101 ····················_SINGLETONS_UNDER_CONSTRUCTION.discard(normalized)96 ····················_SINGLETONS_UNDER_CONSTRUCTION.discard(normalized)
102 ················if·os.getpid()·!=·construction_pid:··#·pragma:·needs·fork97 ················if·os.getpid()·!=·construction_pid:··#·pragma:·needs·fork
103 ····················msg·=·"Lock·construction·cannot·continue·after·fork;·construct·a·new·lock·in·the·child"98 ····················msg·=·"Lock·construction·cannot·continue·after·fork;·construct·a·new·lock·in·the·child"
104 ····················raise·RuntimeError(msg)99 ····················raise·RuntimeError(msg)
105 ················cls._instances[normalized]·=·instance100 ················cls._instances[normalized]·=·instance
 101 ············elif·(
 102 ················_timeout_behavior(instance.timeout,·any_negative=False)
 103 ················!=·_timeout_behavior(timeout,·any_negative=False)
106 ············elif·instance.timeout·!=·timeout·or·instance.blocking·!=·blocking:104 ················or·instance.blocking·!=·blocking
 105 ············):
107 ················msg·=·(106 ················msg·=·(
108 ····················f"Singleton·lock·created·with·timeout={instance.timeout},·blocking={instance.blocking},"107 ····················f"Singleton·lock·created·with·timeout={instance.timeout},·blocking={instance.blocking},"
109 ····················f"·cannot·be·changed·to·timeout={timeout},·blocking={blocking}"108 ····················f"·cannot·be·changed·to·timeout={timeout},·blocking={blocking}"
110 ················)109 ················)
Max diff block lines reached; 55213/60862 bytes (90.72%) of diff not shown.
⊟
561 B
reportlab/__init__.py
    
Offset 1, 13 lines modifiedOffset 1, 13 lines modified
1 #Copyright·ReportLab·Europe·Ltd.·2000-20261 #Copyright·ReportLab·Europe·Ltd.·2000-2026
2 #see·license.txt·for·license·details2 #see·license.txt·for·license·details
3 __doc__="""The·Reportlab·PDF·generation·library."""3 __doc__="""The·Reportlab·PDF·generation·library."""
4 Version·=·"5.0.0"4 Version·=·"5.0.1"
5 __version__=Version5 __version__=Version
6 __date__='20260618'6 __date__='20260820'
  
7 import·sys,·os7 import·sys,·os
  
8 __min_python_version__·=·(3,9)8 __min_python_version__·=·(3,9)
9 if·sys.version_info<·__min_python_version__:9 if·sys.version_info<·__min_python_version__:
10 ····raise·ImportError("""reportlab·requires·%s.%s+;·other·versions·are·unsupported.10 ····raise·ImportError("""reportlab·requires·%s.%s+;·other·versions·are·unsupported.
11 If·you·want·to·try·with·other·python·versions·edit·line·10·of·reportlab/__init__11 If·you·want·to·try·with·other·python·versions·edit·line·10·of·reportlab/__init__
⊟
646 B
reportlab/graphics/renderPDF.py
    
Offset 291, 15 lines modifiedOffset 291, 15 lines modified
291 ····an·A4·page·with·a·title·above·it·-·possibly·overflowing291 ····an·A4·page·with·a·title·above·it·-·possibly·overflowing
292 ····if·too·big."""292 ····if·too·big."""
293 ····d·=·renderScaledDrawing(d)293 ····d·=·renderScaledDrawing(d)
294 ····for·x·in·('Name','Size'):294 ····for·x·in·('Name','Size'):
295 ········a·=·'initialFont'+x295 ········a·=·'initialFont'+x
296 ········kwds[a]·=·getattr(d,a,kwds.pop(a,STATE_DEFAULTS['font'+x]))296 ········kwds[a]·=·getattr(d,a,kwds.pop(a,STATE_DEFAULTS['font'+x]))
297 ····metadataPath·=·kwds.pop('metadataPath',None)297 ····metadataPath·=·kwds.pop('metadataPath',None)
298 ····c·=·Canvas(fn,**kwds)298 ····c·=·kwds.pop('canvasMaker',Canvas)(fn,**kwds)
299 ····if·msg:299 ····if·msg:
300 ········c.setFont(rl_config.defaultGraphicsFontName,·36)300 ········c.setFont(rl_config.defaultGraphicsFontName,·36)
301 ········c.drawString(80,·750,·msg)301 ········c.drawString(80,·750,·msg)
302 ····c.setTitle(msg)302 ····c.setTitle(msg)
  
303 ····if·autoSize:303 ····if·autoSize:
304 ········c.setPageSize((d.width,·d.height))304 ········c.setPageSize((d.width,·d.height))
⊟
3.3 KB
reportlab/lib/rl_safe_eval.py
    
Offset 5, 14 lines modifiedOffset 5, 19 lines modified
5 #hopefully·we·are·standing·on·giants'·shoulders5 #hopefully·we·are·standing·on·giants'·shoulders
6 import·sys,·os,·ast,·re,·weakref,·time,·copy,·math,·types6 import·sys,·os,·ast,·re,·weakref,·time,·copy,·math,·types
7 eval_debug·=·int(os.environ.get('EVAL_DEBUG','0'))7 eval_debug·=·int(os.environ.get('EVAL_DEBUG','0'))
8 strTypes·=·(bytes,str)8 strTypes·=·(bytes,str)
9 isPy39·=·sys.version_info[:2]>=(3,9)9 isPy39·=·sys.version_info[:2]>=(3,9)
10 isPy313·=·sys.version_info[:2]>=(3,13)10 isPy313·=·sys.version_info[:2]>=(3,13)
  
 11 try:
 12 »       GenericAlias·=·types.GenericAlias
 13 except:
 14 »       GenericAlias·=·None
  
11 import·textwrap15 import·textwrap
  
12 class·BadCode(ValueError):16 class·BadCode(ValueError):
13 »       pass17 »       pass
  
14 #·For·AugAssign·the·operator·must·be·converted·to·a·string.18 #·For·AugAssign·the·operator·must·be·converted·to·a·string.
15 augOps·=·{19 augOps·=·{
Offset 915, 24 lines modifiedOffset 920, 26 lines modified
915 »       »       #these·are·used·in·the·tree·visitor920 »       »       #these·are·used·in·the·tree·visitor
916 »       »       __rl_builtins__['__rl_add__']·=·self.__rl_add__921 »       »       __rl_builtins__['__rl_add__']·=·self.__rl_add__
917 »       »       __rl_builtins__['__rl_mult__']·=·self.__rl_mult__922 »       »       __rl_builtins__['__rl_mult__']·=·self.__rl_mult__
918 »       »       __rl_builtins__['__rl_pow__']·=·self.__rl_pow__923 »       »       __rl_builtins__['__rl_pow__']·=·self.__rl_pow__
919 »       »       __rl_builtins__['__rl_sd__']·=·self.__rl_sd__924 »       »       __rl_builtins__['__rl_sd__']·=·self.__rl_sd__
920 »       »       __rl_builtins__['__rl_augAssign__']·=·self.__rl_augAssign__925 »       »       __rl_builtins__['__rl_augAssign__']·=·self.__rl_augAssign__
921 »       »       __rl_builtins__['__rl_getitem__']·=·self.__rl_getitem__926 »       »       __rl_builtins__['__rl_getitem__']·=·self.__rl_getitem__
 927 »       »       __rl_builtins__['__rl_setattr__']·=·self.__rl_setattr__
922 »       »       __rl_builtins__['__rl_getattr__']·=·self.__rl_getattr__928 »       »       __rl_builtins__['__rl_getattr__']·=·self.__rl_getattr__
923 »       »       __rl_builtins__['__rl_getiter__']·=·self.__rl_getiter__929 »       »       __rl_builtins__['__rl_getiter__']·=·self.__rl_getiter__
924 »       »       __rl_builtins__['__rl_max_len__']·=·self.__rl_max_len__930 »       »       __rl_builtins__['__rl_max_len__']·=·self.__rl_max_len__
925 »       »       __rl_builtins__['__rl_max_pow_digits__']·=·self.__rl_max_pow_digits__931 »       »       __rl_builtins__['__rl_max_pow_digits__']·=·self.__rl_max_pow_digits__
926 »       »       __rl_builtins__['__rl_iter_unpack_sequence__']·=·self.__rl_iter_unpack_sequence__932 »       »       __rl_builtins__['__rl_iter_unpack_sequence__']·=·self.__rl_iter_unpack_sequence__
927 »       »       __rl_builtins__['__rl_unpack_sequence__']·=·self.__rl_unpack_sequence__933 »       »       __rl_builtins__['__rl_unpack_sequence__']·=·self.__rl_unpack_sequence__
928 »       »       __rl_builtins__['__rl_apply__']·=·lambda·func,*args,**kwds:·self.__rl_apply__(func,args,kwds)934 »       »       __rl_builtins__['__rl_apply__']·=·lambda·func,*args,**kwds:·self.__rl_apply__(func,args,kwds)
929 »       »       __rl_builtins__['__rl_SafeIter__']·=·__rl_SafeIter__935 »       »       __rl_builtins__['__rl_SafeIter__']·=·__rl_SafeIter__
  
930 »       »       #these·are·tested·builtins936 »       »       #these·are·tested·builtins
 937 »       »       __rl_builtins__['setattr']·=·self.__rl_setattr__
931 »       »       __rl_builtins__['getattr']·=·self.__rl_getattr__938 »       »       __rl_builtins__['getattr']·=·self.__rl_getattr__
932 »       »       __rl_builtins__['dict']·=·__rl_dict__939 »       »       __rl_builtins__['dict']·=·__rl_dict__
933 »       »       __rl_builtins__['iter']·=·self.__rl_getiter__940 »       »       __rl_builtins__['iter']·=·self.__rl_getiter__
934 »       »       __rl_builtins__['pow']·=·self.__rl_pow__941 »       »       __rl_builtins__['pow']·=·self.__rl_pow__
935 »       »       __rl_builtins__['list']·=·self.__rl_list__942 »       »       __rl_builtins__['list']·=·self.__rl_list__
936 »       »       __rl_builtins__['type']·=·self.__rl_type__943 »       »       __rl_builtins__['type']·=·self.__rl_type__
937 »       »       __rl_builtins__['max']·=·self.__rl_max__944 »       »       __rl_builtins__['max']·=·self.__rl_max__
Offset 1071, 15 lines modifiedOffset 1078, 20 lines modified
  
1071 »       def·__rl_getattr__(self,·obj,·a,·*args):1078 »       def·__rl_getattr__(self,·obj,·a,·*args):
1072 »       »       if·isinstance(obj,·strTypes)·and·a=='format':1079 »       »       if·isinstance(obj,·strTypes)·and·a=='format':
1073 »       »       »       raise·BadCode('%s.format·is·not·implemented'·%·type(obj))1080 »       »       »       raise·BadCode('%s.format·is·not·implemented'·%·type(obj))
1074 »       »       self.__rl_is_allowed_name__(a)1081 »       »       self.__rl_is_allowed_name__(a)
1075 »       »       return·getattr(obj,a,*args)1082 »       »       return·getattr(obj,a,*args)
  
 1083 »       def·__rl_setattr__(self,·obj,·a,·v,·*args):
 1084 »       »       #remediation·for·using·odd·magics
 1085 »       »       self.__rl_is_allowed_name__(a)
 1086 »       »       return·setattr(obj,a,v,*args)
  
1076 »       def·__rl_getitem__(self,·obj,·a):1087 »       def·__inner_rl_getitem__(self,·obj,·a):
1077 »       »       if·type(a)·is·self.__slicetype__:1088 »       »       if·type(a)·is·self.__slicetype__:
1078 »       »       »       if·a.step·is·not·None:1089 »       »       »       if·a.step·is·not·None:
1079 »       »       »       »       v·=·obj[a]1090 »       »       »       »       v·=·obj[a]
1080 »       »       »       else:1091 »       »       »       else:
1081 »       »       »       »       start·=·a.start1092 »       »       »       »       start·=·a.start
1082 »       »       »       »       stop·=·a.stop1093 »       »       »       »       stop·=·a.stop
1083 »       »       »       »       if·start·is·None:1094 »       »       »       »       if·start·is·None:
Offset 1090, 14 lines modifiedOffset 1102, 25 lines modified
1090 »       »       »       »       »       v·=·obj[start:stop]1102 »       »       »       »       »       v·=·obj[start:stop]
1091 »       »       »       return·v1103 »       »       »       return·v
1092 »       »       elif·isinstance(a,strTypes):1104 »       »       elif·isinstance(a,strTypes):
1093 »       »       »       self.__rl_is_allowed_name__(a)1105 »       »       »       self.__rl_is_allowed_name__(a)
1094 »       »       »       return·obj[a]1106 »       »       »       return·obj[a]
1095 »       »       return·obj[a]1107 »       »       return·obj[a]
  
 1108 »       def·__rl_getitem__(self,·obj,·a):
 1109 »       »       try:
 1110 »       »       »       v·=·self.__inner_rl_getitem__(obj,a)
 1111 »       »       except·(IndexError,KeyError,KeyboardInterrupt,ValueError,TypeError):
 1112 »       »       »       raise
 1113 »       »       except:
 1114 »       »       »       raise·BadCode("subscript·operation·%s[%r]·failed"·%·(obj.__class__.__name__,a))
 1115 »       »       if·isinstance(v,GenericAlias):
 1116 »       »       »       raise·BadCode("subscript·operation·%s[%r]·created·a·GenericAlias"·%·(obj.__class__.__name__,a))
 1117 »       »       return·v
  
1096 »       __rl_tmax__·=·51118 »       __rl_tmax__·=·5
1097 »       __rl_max_len__·=·1000001119 »       __rl_max_len__·=·100000
1098 »       __rl_max_pow_digits__·=·1001120 »       __rl_max_pow_digits__·=·100
  
1099 »       def·__rl_add__(self,·a,·b):1121 »       def·__rl_add__(self,·a,·b):
1100 »       »       if·(hasattr(a,·'__len__')·and·hasattr(b,·'__len__')1122 »       »       if·(hasattr(a,·'__len__')·and·hasattr(b,·'__len__')
1101 »       »       »       »       and·(len(a)·+·len(b))·>·self.__rl_max_len__):1123 »       »       »       »       and·(len(a)·+·len(b))·>·self.__rl_max_len__):
⊟
6.54 KB
reportlab/lib/utils.py
    
Offset 467, 21 lines modifiedOffset 467, 16 lines modified
467 ········#the·dirname(reportlab.__file__)·or·is·relative467 ········#the·dirname(reportlab.__file__)·or·is·relative
468 ········name·=·_startswith_rl(name)468 ········name·=·_startswith_rl(name)
469 ········s·=·__rl_loader__.get_data(name)469 ········s·=·__rl_loader__.get_data(name)
470 ········if·'b'·not·in·mode·and·os.linesep!='\n':·s·=·s.replace(os.linesep,'\n')470 ········if·'b'·not·in·mode·and·os.linesep!='\n':·s·=·s.replace(os.linesep,'\n')
471 ········return·BytesIO(s)471 ········return·BytesIO(s)
  
472 from·urllib.parse·import·unquote,·urlparse472 from·urllib.parse·import·unquote,·urlparse
473 from·urllib.request·import·urlopen,·Request473 _tHaS·=·{}··#cache·for·(trustedHosts,trustedSchemes)
474 def·rlUrlRead(name,·headers=None):474 def·rlUrlRead(url,·headers=None):
475 ····if·headers==None:·headers·=·{} 
476 ····headers.setdefault('User-Agent','ReportLabAgent') 
477 ····return·urlopen(Request(name,headers=headers)).read() 
  
478 def·open_for_read(name,mode='b'): 
479 ····#auto·initialized·function`475 ····#auto·initialized·function`
480 ····#copied·here·from·urllib.URLopener.open_data·because476 ····#copied·here·from·urllib.URLopener.open_data·because
481 ····#·1)·they·want·to·remove·it477 ····#·1)·they·want·to·remove·it
482 ····#·2)·the·existing·one·is·borken478 ····#·2)·the·existing·one·is·borken
483 ····def·datareader(url,·unquote=unquote):479 ····def·datareader(url,·unquote=unquote):
484 ········"""Use·"data"·URL."""480 ········"""Use·"data"·URL."""
485 ········#·ignore·POSTed·data481 ········#·ignore·POSTed·data
Offset 505, 49 lines modifiedOffset 500, 77 lines modified
505 ············encoding·=·''500 ············encoding·=·''
506 ········if·encoding·==·'base64':501 ········if·encoding·==·'base64':
507 ············#·XXX·is·this·encoding/decoding·ok?502 ············#·XXX·is·this·encoding/decoding·ok?
508 ············data·=·base64_decodebytes(data.encode('ascii'))503 ············data·=·base64_decodebytes(data.encode('ascii'))
509 ········else:504 ········else:
510 ············data·=·unquote(data).encode('latin-1')505 ············data·=·unquote(data).encode('latin-1')
511 ········return·data506 ········return·data
512 ····from·reportlab.rl_config·import·trustedHosts,·trustedSchemes 
513 ····if·trustedHosts:507 ····import·socket
 508 ····from·urllib.request·import·OpenerDirector,·build_opener,·Request
514 ········import·re,·fnmatch509 ····import·re,·fnmatch
515 ········def·xre(s):510 ····def·xre(s):
516 ············s·=·fnmatch.translate(s)511 ········s·=·fnmatch.translate(s)
517 ············return·s[4:-3]·if·s.startswith('(?s:')·else·s[:-7]512 ········return·s[4:-3]·if·s.startswith('(?s:')·else·s[:-7]
 513 ····def·keyval(v):
 514 ········return·v·if·v·is·None·else·tuple(v)
 515 ····class·RLOpenerDirector(OpenerDirector):
 516 ········def·open(self,·req,·data=None,·timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
 517 ············if·isinstance(req,·str):
 518 ················req·=·Request(url,·data)
 519 ············url·=·req.full_url
 520 ············if·data·is·not·None:
 521 ················req.data·=·data
 522 ············#do·the·import·here·in·case·these·change·between·calls
 523 ············from·reportlab.rl_config·import·trustedHosts,·trustedSchemes
 524 ············key·=·keyval(trustedHosts),keyval(trustedSchemes)
 525 ············if·key·not·in·_tHaS:
 526 ················if·trustedHosts:
518 ········trustedHosts·=·re.compile(''.join(('^(?:',527 ····················tHosts·=·re.compile(''.join(('^(?:',
519 ································'|'.join(map(xre,trustedHosts)),528 ············································'|'.join(map(xre,trustedHosts)),
 529 ············································')\\Z')))
 530 ················_tHaS.clear()
 531 ················_tHaS[key]·=·(tHosts,trustedSchemes)
 532 ············tHosts,·tSchemes·=_tHaS[key]
 533 ············if·not·tHosts:·raise·ValueError
 534 ············netloc·=·urlparse(url)
 535 ············scheme·=·netloc.scheme
 536 ············netloc·=·netloc.netloc.lower()
 537 ············if·(not·scheme·
 538 ················or·scheme·not·in·tSchemes·
 539 ················or·(scheme=='file'·and·not·(
 540 ································(netloc==''·and·tHosts.match('localhost'))
 541 ································or
 542 ································(netloc!=''·and·tHosts.match(netloc))
520 ································')\\Z')))543 ································))
  
521 ····def·open_for_read(name,mode='b'): 
522 ········'''attempt·to·open·a·file·or·URL·for·reading''' 
523 ········if·hasattr(name,'read'):·return·name544 ················or·(scheme·not·in·('data','file')·and·not·tHosts.match(netloc))):
 545 ················raise·ValueError·
 546 ············if·scheme=='data':
 547 ················return·datareader(url)
 548 ············else:
 549 ················return·super().open(req,data=data,timeout=timeout)
 550 ····_rlOpener·=·build_opener()
 551 ····_rlOpener.__class__·=·RLOpenerDirector
 552 ····def·rlUrlRead(url,·headers=None):
524 ········try:553 ········try:
525 ············return·open_for_read_by_name(name,mode)554 ············if·headers==None:·headers·=·{}
 555 ············headers.setdefault('User-Agent','ReportLabAgent')
 556 ············return·_rlOpener.open(Request(url,headers=headers))
526 ········except:557 ········except:
527 ············try: 
528 ················if·not·trustedHosts:·raise·ValueError 
529 ················netloc·=·urlparse(name) 
530 ················scheme·=·netloc.scheme 
531 ················netloc·=·netloc.netloc.lower() 
532 ················if·(not·scheme· 
533 ····················or·scheme·not·in·trustedSchemes· 
534 ····················or·(scheme=='file'·and·not·( 
535 ····································(netloc==''·and·trustedHosts.match('localhost')) 
536 ····································or 
537 ····································(netloc!=''·and·trustedHosts.match(netloc)) 
538 ····································)) 
539 ····················or·(scheme·not·in·('data','file')·and·not·trustedHosts.match(netloc))): 
540 ····················raise·ValueError· 
541 ················return·BytesIO((datareader·if·scheme=='data'·else·rlUrlRead)(name)) 
542 ············except: 
543 ················raise·IOError(f'Cannot·open·resource·{name!r}')558 ············raise·IOError(f'Cannot·open·resource·{url!r}')
544 ····globals()['open_for_read']·=·open_for_read559 ····globals()['rlUrlRead']·=·rlUrlRead
 560 ····return·rlUrlRead(url,headers=headers)
  
 561 def·open_for_read(name,mode='b'):
 562 ····'''attempt·to·open·a·file·or·URL·for·reading'''
 563 ····if·hasattr(name,'read'):·return·name
 564 ····try:
545 ····return·open_for_read(name,mode)565 ········return·open_for_read_by_name(name,mode)
 566 ····except:
 567 ········r·=·rlUrlRead(name)
 568 ········return·BytesIO(r.fp.read())·if·not·isinstance(r,bytes)·else·BytesIO(r)
  
546 def·open_and_read(name,mode='b'):569 def·open_and_read(name,mode='b'):
547 ····f·=·open_for_read(name,mode)570 ····f·=·open_for_read(name,mode)
548 ····if·name·is·not·f·and·hasattr(f,'__exit__'):571 ····if·name·is·not·f·and·hasattr(f,'__exit__'):
549 ········with·f:572 ········with·f:
550 ············return·f.read()573 ············return·f.read()
551 ····else:574 ····else:
Offset 652, 15 lines modifiedOffset 675, 18 lines modified
652 ········else:675 ········else:
653 ············try:676 ············try:
654 ················from·reportlab.rl_config·import·imageReaderFlags677 ················from·reportlab.rl_config·import·imageReaderFlags
655 ················if·imageReaderFlags·!=·0:678 ················if·imageReaderFlags·!=·0:
656 ····················raise·ValueError('imageReaderFlags·values·other·than·0·are·no·longer·supported;·all·images·are·interned·now')679 ····················raise·ValueError('imageReaderFlags·values·other·than·0·are·no·longer·supported;·all·images·are·interned·now')
657 ················fp·=·open_for_read(fileName,'b')680 ················fp·=·open_for_read(fileName,'b')
658 ················if·not·isinstance(fp,·BytesIO):681 ················if·not·isinstance(fp,·BytesIO):
Max diff block lines reached; 333/6655 bytes (5.00%) of diff not shown.
⊟
777 B
reportlab/pdfgen/canvas.py
    
Offset 1304, 15 lines modifiedOffset 1304, 15 lines modified
1304 ····def·getpdfdata(self):1304 ····def·getpdfdata(self):
1305 ········"""Returns·the·PDF·data·that·would·normally·be·written·to·a·file.1305 ········"""Returns·the·PDF·data·that·would·normally·be·written·to·a·file.
1306 ········If·there·is·current·data·a·ShowPage·is·executed·automatically.1306 ········If·there·is·current·data·a·ShowPage·is·executed·automatically.
1307 ········After·this·operation·the·canvas·must·not·be·used·further."""1307 ········After·this·operation·the·canvas·must·not·be·used·further."""
1308 ········if·len(self._code):·self.showPage()1308 ········if·len(self._code):·self.showPage()
1309 ········s·=·self._doc.GetPDFData(self)1309 ········s·=·self._doc.GetPDFData(self)
1310 ········if·isUnicode(s):1310 ········if·isUnicode(s):
1311 ············s·=·s.encode('utf-8')1311 ············s·=·s.encode('latin1')··#this·is·what·pdfdoc.py·uses;·could·not·detect·need·in·tests
1312 ········return·s1312 ········return·s
  
1313 ····def·setPageSize(self,·size):1313 ····def·setPageSize(self,·size):
1314 ········"""accepts·a·2-tuple·in·points·for·paper·size·for·this1314 ········"""accepts·a·2-tuple·in·points·for·paper·size·for·this
1315 ········and·subsequent·pages"""1315 ········and·subsequent·pages"""
1316 ········self._pagesize·=·size1316 ········self._pagesize·=·size
1317 ········self._make_preamble()1317 ········self._make_preamble()
⊟
6.37 KB
soupsieve/__init__.py
    
Offset 26, 33 lines modifiedOffset 26, 35 lines modified
26 SOFTWARE.26 SOFTWARE.
27 """27 """
28 from·__future__·import·annotations28 from·__future__·import·annotations
29 from·.__meta__·import·__version__,·__version_info__··#·noqa:·F40129 from·.__meta__·import·__version__,·__version_info__··#·noqa:·F401
30 from·.·import·css_parser·as·cp30 from·.·import·css_parser·as·cp
31 from·.·import·css_match·as·cm31 from·.·import·css_match·as·cm
32 from·.·import·css_types·as·ct32 from·.·import·css_types·as·ct
33 from·.util·import·DEBUG,·SelectorSyntaxError··#·noqa:·F40133 from·.util·import·DEBUG,·NOCACHE,·NOSTRICT,·SelectorSyntaxError··#·noqa:·F401
34 import·bs434 import·bs4
35 from·typing·import·Any,·Iterator,·Iterable35 from·typing·import·Any,·Mapping,·Iterator,·Iterable,·cast
  
36 __all__·=·(36 __all__·=·(
 37 ····'DEBUG',·'NOCACHE',·'NOSTRICT',·'SelectorSyntaxError',·'CustomSelectors',·'SoupSieve',
 38 ····'closest',·'compile',·'filter',·'iselect',·'match',·'select',·'select_one'
37 ····'DEBUG',·'SelectorSyntaxError',·'SoupSieve', 
38 ····'closest',·'compile',·'filter',·'iselect', 
39 ····'match',·'select',·'select_one' 
40 )39 )
  
41 SoupSieve·=·cm.SoupSieve40 SoupSieve·=·cm.SoupSieve
 41 CustomSelectors·=·ct.CustomSelectors
  
  
42 def·compile(··#·noqa:·A00142 def·compile(··#·noqa:·A001
43 ····pattern:·str,43 ····pattern:·str,
44 ····namespaces:·dict[str,·str]·|·None·=·None,44 ····namespaces:·dict[str,·str]·|·None·=·None,
45 ····flags:·int·=·0,45 ····flags:·int·=·0,
46 ····*,46 ····*,
47 ····custom:·dict[str,·str]·|·None·=·None,47 ····custom:·Mapping[str,·str·|·ct.SelectorList]·|·None·=·None,
 48 ····ignore:·Iterable[str]·|·None·=·None,
 49 ····max_selectors:·int·=·cp.SELECTOR_LIMIT,
48 ····**kwargs:·Any50 ····**kwargs:·Any
49 )·->·cm.SoupSieve:51 )·->·cm.SoupSieve:
50 ····"""Compile·CSS·pattern."""52 ····"""Compile·CSS·pattern."""
  
51 ····if·isinstance(pattern,·SoupSieve):53 ····if·isinstance(pattern,·SoupSieve):
52 ········if·flags:54 ········if·flags:
53 ············raise·ValueError("Cannot·process·'flags'·argument·on·a·compiled·selector·list")55 ············raise·ValueError("Cannot·process·'flags'·argument·on·a·compiled·selector·list")
Offset 61, 16 lines modifiedOffset 63, 20 lines modified
61 ········elif·custom·is·not·None:63 ········elif·custom·is·not·None:
62 ············raise·ValueError("Cannot·process·'custom'·argument·on·a·compiled·selector·list")64 ············raise·ValueError("Cannot·process·'custom'·argument·on·a·compiled·selector·list")
63 ········return·pattern65 ········return·pattern
  
64 ····return·cp._cached_css_compile(66 ····return·cp._cached_css_compile(
65 ········pattern,67 ········pattern,
66 ········ct.Namespaces(namespaces)·if·namespaces·is·not·None·else·namespaces,68 ········ct.Namespaces(namespaces)·if·namespaces·is·not·None·else·namespaces,
67 ········ct.CustomSelectors(custom)·if·custom·is·not·None·else·custom,69 ········ct.CustomSelectors(
 70 ············cast('dict[str,·str·|·ct.SelectorList]',·custom),·max_selectors=max_selectors
 71 ········)·if·custom·is·not·None·and·not·isinstance(custom,·ct.CustomSelectors)·else·custom,
 72 ········tuple(i.lower()·for·i·in·ignore)·if·ignore·is·not·None·else·ignore,
68 ········flags73 ········flags,
 74 ········max_selectors
69 ····)75 ····)
  
  
70 def·purge()·->·None:76 def·purge()·->·None:
71 ····"""Purge·cached·patterns."""77 ····"""Purge·cached·patterns."""
  
72 ····cp._purge_cache()78 ····cp._purge_cache()
Offset 78, 91 lines modifiedOffset 84, 151 lines modified
  
78 def·closest(84 def·closest(
79 ····select:·str,85 ····select:·str,
80 ····tag:·bs4.Tag,86 ····tag:·bs4.Tag,
81 ····namespaces:·dict[str,·str]·|·None·=·None,87 ····namespaces:·dict[str,·str]·|·None·=·None,
82 ····flags:·int·=·0,88 ····flags:·int·=·0,
83 ····*,89 ····*,
84 ····custom:·dict[str,·str]·|·None·=·None,90 ····custom:·Mapping[str,·str·|·ct.SelectorList]·|·None·=·None,
 91 ····ignore:·Iterable[str]·|·None·=·None,
 92 ····max_selectors:·int·=·cp.SELECTOR_LIMIT,
85 ····**kwargs:·Any93 ····**kwargs:·Any
86 )·->·bs4.Tag·|·None:94 )·->·bs4.Tag·|·None:
87 ····"""Match·closest·ancestor."""95 ····"""Match·closest·ancestor."""
  
88 ····return·compile(select,·namespaces,·flags,·**kwargs).closest(tag)96 ····return·compile(
 97 ········select,
 98 ········namespaces,
 99 ········flags,
 100 ········custom=custom,
 101 ········ignore=ignore,
 102 ········max_selectors=max_selectors,
 103 ········**kwargs
 104 ····).closest(tag)
  
  
89 def·match(105 def·match(
90 ····select:·str,106 ····select:·str,
91 ····tag:·bs4.Tag,107 ····tag:·bs4.Tag,
92 ····namespaces:·dict[str,·str]·|·None·=·None,108 ····namespaces:·dict[str,·str]·|·None·=·None,
93 ····flags:·int·=·0,109 ····flags:·int·=·0,
94 ····*,110 ····*,
95 ····custom:·dict[str,·str]·|·None·=·None,111 ····custom:·Mapping[str,·str·|·ct.SelectorList]·|·None·=·None,
 112 ····ignore:·Iterable[str]·|·None·=·None,
 113 ····max_selectors:·int·=·cp.SELECTOR_LIMIT,
96 ····**kwargs:·Any114 ····**kwargs:·Any
97 )·->·bool:115 )·->·bool:
98 ····"""Match·node."""116 ····"""Match·node."""
  
99 ····return·compile(select,·namespaces,·flags,·**kwargs).match(tag)117 ····return·compile(
 118 ········select,
 119 ········namespaces,
 120 ········flags,
 121 ········custom=custom,
 122 ········ignore=ignore,
 123 ········max_selectors=max_selectors,
 124 ········**kwargs
 125 ····).match(tag)
  
  
100 def·filter(··#·noqa:·A001126 def·filter(··#·noqa:·A001
101 ····select:·str,127 ····select:·str,
102 ····iterable:·Iterable[bs4.Tag],128 ····iterable:·Iterable[bs4.Tag],
103 ····namespaces:·dict[str,·str]·|·None·=·None,129 ····namespaces:·dict[str,·str]·|·None·=·None,
104 ····flags:·int·=·0,130 ····flags:·int·=·0,
105 ····*,131 ····*,
106 ····custom:·dict[str,·str]·|·None·=·None,132 ····custom:·Mapping[str,·str·|·ct.SelectorList]·|·None·=·None,
 133 ····ignore:·Iterable[str]·|·None·=·None,
 134 ····max_selectors:·int·=·cp.SELECTOR_LIMIT,
107 ····**kwargs:·Any135 ····**kwargs:·Any
108 )·->·list[bs4.Tag]:136 )·->·list[bs4.Tag]:
109 ····"""Filter·list·of·nodes."""137 ····"""Filter·list·of·nodes."""
  
110 ····return·compile(select,·namespaces,·flags,·**kwargs).filter(iterable)138 ····return·compile(
 139 ········select,
 140 ········namespaces,
 141 ········flags,
 142 ········custom=custom,
Max diff block lines reached; 2201/6480 bytes (33.97%) of diff not shown.
⊟
355 B
soupsieve/__meta__.py
    
Offset 189, 9 lines modifiedOffset 189, 9 lines modified
  
189 ····#·Handle·post189 ····#·Handle·post
190 ····post·=·int(m.group('post'))·if·m.group('post')·else·0190 ····post·=·int(m.group('post'))·if·m.group('post')·else·0
  
191 ····return·Version(major,·minor,·micro,·release,·pre,·post,·dev)191 ····return·Version(major,·minor,·micro,·release,·pre,·post,·dev)
  
  
192 __version_info__·=·Version(2,·9,·1,·"final")192 __version_info__·=·Version(3,·0,·3,·"final")
193 __version__·=·__version_info__._get_canonical()193 __version__·=·__version_info__._get_canonical()
⊟
48.5 KB
soupsieve/css_match.py
    
Offset 1, 16 lines modifiedOffset 1, 28 lines modified
1 """CSS·matcher."""1 """CSS·matcher."""
2 from·__future__·import·annotations2 from·__future__·import·annotations
3 from·datetime·import·datetime3 from·datetime·import·datetime
 4 from·collections.abc·import·Hashable
4 from·.·import·util5 from·.·import·util
5 import·re6 import·re
6 from·.·import·css_types·as·ct7 from·.·import·css_types·as·ct
7 import·unicodedata8 import·unicodedata
8 import·bs49 import·bs4
9 from·typing·import·Iterator,·Iterable,·Any,·Callable,·Sequence,·Any,·cast··#·noqa:·F401,·F81110 from·typing·import·(
 11 ····Generator,
 12 ····Iterator,
 13 ····Iterable,
 14 ····Any,
 15 ····Callable,
 16 ····Sequence,
 17 ····overload,
 18 ····Literal,
 19 ····cast,
 20 ····TYPE_CHECKING
 21 )··#·noqa:·F401,·F811
  
10 #·Empty·tag·pattern·(whitespace·okay)22 #·Empty·tag·pattern·(whitespace·okay)
11 RE_NOT_EMPTY·=·re.compile('[^·\t\r\n\f]')23 RE_NOT_EMPTY·=·re.compile('[^·\t\r\n\f]')
  
12 RE_NOT_WS·=·re.compile('[^·\t\r\n\f]+')24 RE_NOT_WS·=·re.compile('[^·\t\r\n\f]+')
  
13 #·Relationships25 #·Relationships
Offset 21, 14 lines modifiedOffset 33, 20 lines modified
  
21 #·Relationships·for·:has()·(forward·looking)33 #·Relationships·for·:has()·(forward·looking)
22 REL_HAS_PARENT·=·':·'34 REL_HAS_PARENT·=·':·'
23 REL_HAS_CLOSE_PARENT·=·':>'35 REL_HAS_CLOSE_PARENT·=·':>'
24 REL_HAS_SIBLING·=·':~'36 REL_HAS_SIBLING·=·':~'
25 REL_HAS_CLOSE_SIBLING·=·':+'37 REL_HAS_CLOSE_SIBLING·=·':+'
  
 38 #·`bs4`·imports·this·module·while·it·is·still·initializing,
 39 #·so·these·must·only·be·evaluated·when·type·checking.
 40 if·TYPE_CHECKING:··#·pragma:·no·cover
 41 ····MatchRequest·=·tuple[bs4.Tag,·ct.SelectorList]
 42 ····MatchGenerator·=·Generator[MatchRequest,·bool,·bool]
  
26 NS_XHTML·=·'http://www.w3.org/1999/xhtml'43 NS_XHTML·=·'http://www.w3.org/1999/xhtml'
27 NS_XML·=·'http://www.w3.org/XML/1998/namespace'44 NS_XML·=·'http://www.w3.org/XML/1998/namespace'
  
28 DIR_FLAGS·=·ct.SEL_DIR_LTR·|·ct.SEL_DIR_RTL45 DIR_FLAGS·=·ct.SEL_DIR_LTR·|·ct.SEL_DIR_RTL
29 RANGES·=·ct.SEL_IN_RANGE·|·ct.SEL_OUT_OF_RANGE46 RANGES·=·ct.SEL_IN_RANGE·|·ct.SEL_OUT_OF_RANGE
  
30 DIR_MAP·=·{47 DIR_MAP·=·{
Offset 52, 32 lines modifiedOffset 70, 19 lines modified
52 SHORT_MONTH·=·3070 SHORT_MONTH·=·30
53 LONG_MONTH·=·3171 LONG_MONTH·=·31
54 FEB_MONTH·=·2872 FEB_MONTH·=·28
55 FEB_LEAP_MONTH·=·2973 FEB_LEAP_MONTH·=·29
56 DAYS_IN_WEEK·=·774 DAYS_IN_WEEK·=·7
  
  
 75 def·within(target:·bs4.Tag,·parent:·bs4.Tag·|·bs4.BeautifulSoup,·start:·int,·end:·int·|·None·=·None)·->·bool:
 76 ····"""Check·if·target·is·within·data."""
57 class·_FakeParent: 
58 ····""" 
59 ····Fake·parent·class. 
  
60 ····When·we·have·a·fragment·with·no·`BeautifulSoup`·document·object, 
61 ····we·can't·evaluate·`nth`·selectors·properly.··Create·a·temporary 
62 ····fake·parent·so·we·can·traverse·the·root·element·as·a·child. 
63 ····""" 
  
64 ····def·__init__(self,·element:·bs4.Tag)·->·None: 
65 ········"""Initialize.""" 
  
66 ········self.contents·=·[element] 
  
67 ····def·__len__(self)·->·int: 
68 ········"""Length.""" 
  
69 ········return·len(self.contents)77 ····contents·=·parent.contents
 78 ····return·any(contents[i]·is·target·for·i·in·range(start,·end·if·end·is·not·None·else·len(contents)))
  
  
70 class·_DocumentNav:79 class·_DocumentNav:
71 ····"""Navigate·a·Beautiful·Soup·document."""80 ····"""Navigate·a·Beautiful·Soup·document."""
  
72 ····@classmethod81 ····@classmethod
73 ····def·assert_valid_input(cls,·tag:·Any)·->·None:82 ····def·assert_valid_input(cls,·tag:·Any)·->·None:
Offset 125, 20 lines modifiedOffset 130, 14 lines modified
125 ····@classmethod130 ····@classmethod
126 ····def·is_content_string(cls,·obj:·bs4.element.PageElement·|·None)·->·bool:131 ····def·is_content_string(cls,·obj:·bs4.element.PageElement·|·None)·->·bool:
127 ········"""Check·if·node·is·content·string."""132 ········"""Check·if·node·is·content·string."""
  
128 ········return·cls.is_navigable_string(obj)·and·not·cls.is_special_string(obj)133 ········return·cls.is_navigable_string(obj)·and·not·cls.is_special_string(obj)
  
129 ····@staticmethod134 ····@staticmethod
130 ····def·create_fake_parent(el:·bs4.Tag)·->·_FakeParent: 
131 ········"""Create·fake·parent·for·a·given·element.""" 
  
132 ········return·_FakeParent(el) 
  
133 ····@staticmethod 
134 ····def·is_xml_tree(el:·bs4.Tag·|·None)·->·bool:135 ····def·is_xml_tree(el:·bs4.Tag·|·None)·->·bool:
135 ········"""Check·if·element·(or·document)·is·from·a·XML·tree."""136 ········"""Check·if·element·(or·document)·is·from·a·XML·tree."""
  
136 ········return·el·is·not·None·and·bool(el._is_xml)137 ········return·el·is·not·None·and·bool(el._is_xml)
  
137 ····def·is_iframe(self,·el:·bs4.Tag·|·None)·->·bool:138 ····def·is_iframe(self,·el:·bs4.Tag·|·None)·->·bool:
138 ········"""Check·if·element·is·an·`iframe`."""139 ········"""Check·if·element·is·an·`iframe`."""
Offset 177, 39 lines modifiedOffset 176, 60 lines modified
177 ········el:·bs4.Tag·|·None,176 ········el:·bs4.Tag·|·None,
178 ········start:·int·|·None·=·None,177 ········start:·int·|·None·=·None,
179 ········reverse:·bool·=·False,178 ········reverse:·bool·=·False,
180 ········no_iframe:·bool·=·False179 ········no_iframe:·bool·=·False
181 ····)·->·Iterator[bs4.Tag]:180 ····)·->·Iterator[bs4.Tag]:
182 ········"""Get·tag·children."""181 ········"""Get·tag·children."""
  
183 ········return·self.get_children(el,·start,·reverse,·True,·no_iframe)··#·type:·ignore[return-value]182 ········return·self.get_children(el,·start,·reverse,·True,·no_iframe)
  
 183 ····@overload
184 ····def·get_children(184 ····def·get_children(
185 ········self,185 ········self,
186 ········el:·bs4.Tag·|·None,186 ········el:·bs4.Tag·|·None,
187 ········start:·int·|·None·=·None,187 ········start:·int·|·None·=·None,
188 ········reverse:·bool·=·False,188 ········reverse:·bool·=·False,
 189 ········tags:·Literal[True]·=·...,
 190 ········no_iframe:·bool·=·False
 191 ····)·->·Iterator[bs4.Tag]:
 192 ········...
  
Max diff block lines reached; 45372/49602 bytes (91.47%) of diff not shown.
⊟
50.2 KB
soupsieve/css_parser.py
    
Offset 3, 19 lines modifiedOffset 3, 21 lines modified
3 import·re3 import·re
4 from·functools·import·lru_cache4 from·functools·import·lru_cache
5 from·.·import·util5 from·.·import·util
6 from·.·import·css_match·as·cm6 from·.·import·css_match·as·cm
7 from·.·import·css_types·as·ct7 from·.·import·css_types·as·ct
8 from·.util·import·SelectorSyntaxError8 from·.util·import·SelectorSyntaxError
9 import·warnings9 import·warnings
10 from·typing·import·Match,·Any,·Iterator,·cast10 from·typing·import·Match,·Any,·Callable,·Iterator,·Iterable,·Mapping,·cast
11 from·dataclasses·import·dataclass11 from·dataclasses·import·dataclass
12 from·collections·import·UserDict12 from·collections·import·UserDict
13 import·threading13 import·threading
  
 14 __all__·=·('SelectorSyntaxError',)
  
14 RE_LOCK·=·threading.Lock()15 RE_LOCK·=·threading.Lock()
15 SEL_LOCK·=·threading.RLock()16 SEL_LOCK·=·threading.RLock()
  
16 UNICODE_REPLACEMENT_CHAR·=·0xFFFD17 UNICODE_REPLACEMENT_CHAR·=·0xFFFD
  
17 SELECTOR_LIMIT·=·819218 SELECTOR_LIMIT·=·8192
  
Offset 105, 91 lines modifiedOffset 107, 98 lines modified
105 ····':nth-of-type'107 ····':nth-of-type'
106 }108 }
  
107 PSEUDO_SUPPORTED·=·PSEUDO_SIMPLE·|·PSEUDO_SIMPLE_NO_MATCH·|·PSEUDO_COMPLEX·|·PSEUDO_COMPLEX_NO_MATCH·|·PSEUDO_SPECIAL109 PSEUDO_SUPPORTED·=·PSEUDO_SIMPLE·|·PSEUDO_SIMPLE_NO_MATCH·|·PSEUDO_COMPLEX·|·PSEUDO_COMPLEX_NO_MATCH·|·PSEUDO_SPECIAL
  
108 #·Sub-patterns·parts110 #·Sub-patterns·parts
109 #·Whitespace111 #·Whitespace
110 NEWLINE·=·r'(?:\r\n|(?!\r\n)[\n\f\r])'112 NEWLINE·=·r'(?>\r\n|[\n\f\r])'
111 WS·=·fr'(?:[·\t]|{NEWLINE})'113 WS·=·fr'(?:[·\t]|{NEWLINE})'
112 #·Comments114 #·Comments
113 COMMENTS·=·r'(?:/\*(?:[^*]|\*(?!/))*\*/)'115 COMMENTS·=·r'(?:/\*(?:[^*]|\*(?!/))*+\*/)'
114 #·Whitespace·with·comments·included116 #·Whitespace·with·comments·included
115 WSC·=·fr'(?:{WS}|{COMMENTS})'117 WSC·=·fr'(?:{WS}|{COMMENTS})'
116 #·CSS·escapes118 #·CSS·escapes
117 CSS_ESCAPES·=·fr'(?:\\(?:[a-f0-9]{{1,6}}{WS}?|[^\r\n\f]|$))'119 CSS_ESCAPES·=·fr'(?:\\(?:[a-f0-9]{{1,6}}+{WS}?+|[^\r\n\f]|$))'
118 CSS_STRING_ESCAPES·=·fr'(?:\\(?:[a-f0-9]{{1,6}}{WS}?|[^\r\n\f]|$|{NEWLINE}))'120 CSS_STRING_ESCAPES·=·fr'(?:\\(?:[a-f0-9]{{1,6}}+{WS}?+|{NEWLINE}|[^\r\n\f]|$))'
119 #·CSS·Identifier121 #·CSS·Identifier
120 IDENTIFIER·=·fr'''122 IDENTIFIER·=·fr'''
121 (?:(?:--|-?(?:[^\x00-\x2f\x30-\x40\x5B-\x5E\x60\x7B-\x9f]|{CSS_ESCAPES}))123 (?:(?:--|-?+(?:[^\x00-\x2f\x30-\x40\x5B-\x5E\x60\x7B-\x9f]|{CSS_ESCAPES}))
122 (?:[^\x00-\x2c\x2e\x2f\x3A-\x40\x5B-\x5E\x60\x7B-\x9f]|{CSS_ESCAPES})*)124 (?:[^\x00-\x2c\x2e\x2f\x3A-\x40\x5B-\x5E\x60\x7B-\x9f]|{CSS_ESCAPES})*+)
123 '''125 '''
124 #·`nth`·content126 #·`nth`·content
125 NTH·=·fr'(?:[-+])?(?:[0-9]+n?|n)(?:(?<=n){WSC}*(?:[-+]){WSC}*(?:[0-9]+))?'127 NTH·=·fr'[-+]?+(?:[0-9]++n?+|n)(?:(?<=n){WSC}*+[-+]{WSC}*+[0-9]++)?+'
126 #·Value:·quoted·string·or·identifier128 #·Value:·quoted·string·or·identifier
127 VALUE·=·fr'''(?:"(?:\\(?:.|{NEWLINE})|[^\\"\r\n\f])*?"|'(?:\\(?:.|{NEWLINE})|[^\\'\r\n\f])*?'|{IDENTIFIER})'''129 VALUE·=·fr'''
 130 (?:"(?:\\(?:{NEWLINE}|[^\r\n\f])|[^\\"\r\n\f])*+"|
 131 '(?:\\(?:{NEWLINE}|[^\r\n\f])|[^\\'\r\n\f])*+'|
 132 {IDENTIFIER})
 133 '''
128 #·Attribute·value·comparison.·`!=`·is·handled·special·as·it·is·non-standard.134 #·Attribute·value·comparison.·`!=`·is·handled·special·as·it·is·non-standard.
129 ATTR·=·fr'(?:{WSC}*(?P<cmp>[!~^|*$]?=){WSC}*(?P<value>{VALUE})(?:{WSC}*(?P<case>[is]))?)?{WSC}*'135 ATTR·=·fr'(?:{WSC}*+(?P<cmp>[!~^|*$]?+=){WSC}*+(?P<value>{VALUE})(?:{WSC}*+(?P<case>[is]))?+)?+'
  
130 #·Selector·patterns136 #·Selector·patterns
131 #·IDs·(`#id`)137 #·IDs·(`#id`)
132 PAT_ID·=·fr'\#{IDENTIFIER}'138 PAT_ID·=·fr'\#{IDENTIFIER}'
133 #·Classes·(`.class`)139 #·Classes·(`.class`)
134 PAT_CLASS·=·fr'\.{IDENTIFIER}'140 PAT_CLASS·=·fr'\.{IDENTIFIER}'
135 #·Prefix:Tag·(`prefix|tag`)141 #·Prefix:Tag·(`prefix|tag`)
136 PAT_TAG·=·fr'(?P<tag_ns>(?:{IDENTIFIER}|\*)?\|)?(?P<tag_name>{IDENTIFIER}|\*)'142 PAT_TAG·=·fr'(?P<tag_ns>(?:{IDENTIFIER}|\*)?+\|)?+(?P<tag_name>{IDENTIFIER}|\*)'
137 #·Attributes·(`[attr]`,·`[attr=value]`,·etc.)143 #·Attributes·(`[attr]`,·`[attr=value]`,·etc.)
138 PAT_ATTR·=·fr'\[{WSC}*(?P<attr_ns>(?:{IDENTIFIER}|\*)?\|)?(?P<attr_name>{IDENTIFIER}){ATTR}\]'144 PAT_ATTR·=·fr'\[{WSC}*+(?P<attr_ns>(?:{IDENTIFIER}|\*)?+\|(?!=))?+(?P<attr_name>{IDENTIFIER}){ATTR}{WSC}*+\]'
139 #·Pseudo·class·(`:pseudo-class`,·`:pseudo-class(`)145 #·Pseudo·class·(`:pseudo-class`,·`:pseudo-class(`)
140 PAT_PSEUDO_CLASS·=·fr'(?P<name>:{IDENTIFIER})(?P<open>\({WSC}*)?'146 PAT_PSEUDO_CLASS·=·fr'(?P<name>:{IDENTIFIER})(?P<open>\({WSC}*+)?+'
141 #·Pseudo·class·special·patterns.·Matches·`:pseudo-class(`·for·special·case·pseudo·classes.147 #·Pseudo·class·special·patterns.·Matches·`:pseudo-class(`·for·special·case·pseudo·classes.
142 PAT_PSEUDO_CLASS_SPECIAL·=·fr'(?P<name>:{IDENTIFIER})(?P<open>\({WSC}*)'148 PAT_PSEUDO_CLASS_SPECIAL·=·fr'(?P<name>:{IDENTIFIER})(?P<open>\({WSC}*+)'
143 #·Custom·pseudo·class·(`:--custom-pseudo`)149 #·Custom·pseudo·class·(`:--custom-pseudo`)
144 PAT_PSEUDO_CLASS_CUSTOM·=·fr'(?P<name>:(?=--){IDENTIFIER})'150 PAT_PSEUDO_CLASS_CUSTOM·=·fr'(?P<name>:(?=--){IDENTIFIER})'
145 #·Nesting·ampersand·selector.·Matches·`&`151 #·Nesting·ampersand·selector.·Matches·`&`
146 PAT_AMP·=·r'&'152 PAT_AMP·=·r'&'
147 #·Closing·pseudo·group·(`)`)153 #·Closing·pseudo·group·(`)`)
148 PAT_PSEUDO_CLOSE·=·fr'{WSC}*\)'154 PAT_PSEUDO_CLOSE·=·fr'{WSC}*+\)'
149 #·Pseudo·element·(`::pseudo-element`)155 #·Pseudo·element·(`::pseudo-element`)
150 PAT_PSEUDO_ELEMENT·=·fr':{PAT_PSEUDO_CLASS}'156 PAT_PSEUDO_ELEMENT·=·fr':{PAT_PSEUDO_CLASS}'
151 #·At·rule·(`@page`,·etc.)·(not·supported)157 #·At·rule·(`@page`,·etc.)·(not·supported)
152 PAT_AT_RULE·=·fr'@P{IDENTIFIER}'158 PAT_AT_RULE·=·fr'@P{IDENTIFIER}'
153 #·Pseudo·class·`nth-child`·(`:nth-child(an+b·[of·S]?)`,·`:first-child`,·etc.)159 #·Pseudo·class·`nth-child`·(`:nth-child(an+b·[of·S]?)`,·`:first-child`,·etc.)
154 PAT_PSEUDO_NTH_CHILD·=·fr'''160 PAT_PSEUDO_NTH_CHILD·=·fr'''
155 (?P<pseudo_nth_child>{PAT_PSEUDO_CLASS_SPECIAL}161 (?P<pseudo_nth_child>{PAT_PSEUDO_CLASS_SPECIAL}
156 (?P<nth_child>{NTH}|even|odd))(?:{WSC}*\)|(?P<of>{COMMENTS}*{WS}{WSC}*of{COMMENTS}*{WS}{WSC}*))162 (?P<nth_child>{NTH}|even|odd))(?:{WSC}*+\)|(?P<of>{COMMENTS}*+{WS}{WSC}*+of{COMMENTS}*+{WS}{WSC}*+))
157 '''163 '''
158 #·Pseudo·class·`nth-of-type`·(`:nth-of-type(an+b)`,·`:first-of-type`,·etc.)164 #·Pseudo·class·`nth-of-type`·(`:nth-of-type(an+b)`,·`:first-of-type`,·etc.)
159 PAT_PSEUDO_NTH_TYPE·=·fr'''165 PAT_PSEUDO_NTH_TYPE·=·fr'''
160 (?P<pseudo_nth_type>{PAT_PSEUDO_CLASS_SPECIAL}166 (?P<pseudo_nth_type>{PAT_PSEUDO_CLASS_SPECIAL}
161 (?P<nth_type>{NTH}|even|odd)){WSC}*\)167 (?P<nth_type>{NTH}|even|odd)){WSC}*+\)
162 '''168 '''
163 #·Pseudo·class·language·(`:lang("*-de",·en)`)169 #·Pseudo·class·language·(`:lang("*-de",·en)`)
164 PAT_PSEUDO_LANG·=·fr'{PAT_PSEUDO_CLASS_SPECIAL}(?P<values>{VALUE}(?:{WSC}*,{WSC}*{VALUE})*){WSC}*\)'170 PAT_PSEUDO_LANG·=·fr'{PAT_PSEUDO_CLASS_SPECIAL}(?P<values>{VALUE}(?:{WSC}*+,{WSC}*+{VALUE})*+){WSC}*+\)'
165 #·Pseudo·class·direction·(`:dir(ltr)`)171 #·Pseudo·class·direction·(`:dir(ltr)`)
166 PAT_PSEUDO_DIR·=·fr'{PAT_PSEUDO_CLASS_SPECIAL}(?P<dir>ltr|rtl){WSC}*\)'172 PAT_PSEUDO_DIR·=·fr'{PAT_PSEUDO_CLASS_SPECIAL}(?P<dir>ltr|rtl){WSC}*+\)'
167 #·Combining·characters·(`>`,·`~`,·`·`,·`+`,·`,`)173 #·Combining·characters·(`>`,·`~`,·`·`,·`+`,·`,`)
168 PAT_COMBINE·=·fr'{WSC}*?(?P<relation>[,+>~]|{WS}(?![,+>~])){WSC}*'174 PAT_COMBINE·=·fr'{COMMENTS}*+(?={WS}|[,+>~]){WSC}*+(?P<relation>[,+>~])?+{WSC}*+'
169 #·Extra:·Contains·(`:contains(text)`)175 #·Extra:·Contains·(`:contains(text)`)
170 PAT_PSEUDO_CONTAINS·=·fr'{PAT_PSEUDO_CLASS_SPECIAL}(?P<values>{VALUE}(?:{WSC}*,{WSC}*{VALUE})*){WSC}*\)'176 PAT_PSEUDO_CONTAINS·=·fr'{PAT_PSEUDO_CLASS_SPECIAL}(?P<values>{VALUE}(?:{WSC}*+,{WSC}*+{VALUE})*+){WSC}*+\)'
  
171 #·Regular·expressions177 #·Regular·expressions
172 #·CSS·escape·pattern178 #·CSS·escape·pattern
173 RE_CSS_ESC·=·re.compile(fr'(?:(\\[a-f0-9]{{1,6}}{WSC}?)|(\\[^\r\n\f])|(\\$))',·re.I)179 RE_CSS_ESC·=·re.compile(fr'(?:(\\[a-f0-9]{{1,6}}+{WSC}?+)|(\\[^\r\n\f])|(\\$))',·re.I)
174 RE_CSS_STR_ESC·=·re.compile(fr'(?:(\\[a-f0-9]{{1,6}}{WS}?)|(\\[^\r\n\f])|(\\$)|(\\{NEWLINE}))',·re.I)180 RE_CSS_STR_ESC·=·re.compile(fr'(?:(\\[a-f0-9]{{1,6}}+{WS}?+)|(\\[^\r\n\f])|(\\$)|(\\{NEWLINE}))',·re.I)
175 #·Pattern·to·break·up·`nth`·specifiers181 #·Pattern·to·break·up·`nth`·specifiers
176 RE_NTH·=·re.compile(fr'(?P<s1>[-+])?(?P<a>[0-9]+n?|n)(?:(?<=n){WSC}*(?P<s2>[-+]){WSC}*(?P<b>[0-9]+))?',·re.I)182 RE_NTH·=·re.compile(fr'(?P<s1>[-+])?+(?P<a>[0-9]++n?+|n)(?:(?<=n){WSC}*+(?P<s2>[-+]){WSC}*+(?P<b>[0-9]++))?+',·re.I)
177 #·Pattern·to·iterate·multiple·values.183 #·Pattern·to·iterate·multiple·values.
178 RE_VALUES·=·re.compile(fr'(?:(?P<value>{VALUE})|(?P<split>{WSC}*,{WSC}*))',·re.X)184 RE_VALUES·=·re.compile(fr'(?:(?P<value>{VALUE})|(?P<split>{WSC}*+,{WSC}*+))',·re.X)
179 #·Whitespace·checks185 #·Whitespace·checks
180 RE_WS·=·re.compile(WS)186 RE_WS·=·re.compile(WS)
181 RE_WS_BEGIN·=·re.compile(fr'^{WSC}*')187 RE_WS_BEGIN·=·re.compile(fr'^{WSC}*+')
182 RE_WS_END·=·re.compile(fr'^(?:[·\t]|(?:\n\r|(?!\n\r)[\n\f\r])|{COMMENTS})*')188 RE_WS_END·=·re.compile(fr'^(?:[·\t]|(?>\n\r|[\n\f\r])|{COMMENTS})*+')
183 RE_CUSTOM·=·re.compile(fr'^{PAT_PSEUDO_CLASS_CUSTOM}$',·re.X)189 RE_CUSTOM·=·re.compile(fr'^{PAT_PSEUDO_CLASS_CUSTOM}$',·re.X)
184 RE_PSEUDO_CLASS_SPECIAL·=·re.compile(PAT_PSEUDO_CLASS_SPECIAL,·re.I·|·re.X·|·re.U)190 RE_PSEUDO_CLASS_SPECIAL·=·re.compile(PAT_PSEUDO_CLASS_SPECIAL,·re.I·|·re.X·|·re.U)
 191 RE_PSEUDO_IGNORE·=·re.compile(PAT_PSEUDO_CLASS,·re.X·|·re.I·|·re.U)
  
 192 QUOTED·=·("'",·'"')
  
185 #·Constants193 #·Constants
186 #·List·split·token194 #·List·split·token
187 COMMA_COMBINATOR·=·','195 COMMA_COMBINATOR·=·','
188 #·Relation·token·for·descendant196 #·Relation·token·for·descendant
189 WS_COMBINATOR·=·"·"197 WS_COMBINATOR·=·"·"
  
Offset 211, 78 lines modifiedOffset 220, 75 lines modified
  
  
211 @lru_cache(maxsize=_MAXCACHE)220 @lru_cache(maxsize=_MAXCACHE)
212 def·_cached_css_compile(221 def·_cached_css_compile(
213 ····pattern:·str,222 ····pattern:·str,
214 ····namespaces:·ct.Namespaces·|·None,223 ····namespaces:·ct.Namespaces·|·None,
Max diff block lines reached; 44370/51410 bytes (86.31%) of diff not shown.
⊟
16.5 KB
soupsieve/css_types.py
    
Offset 1, 40 lines modifiedOffset 1, 58 lines modified
1 """CSS·selector·structure·items."""1 """CSS·selector·structure·items."""
2 from·__future__·import·annotations2 from·__future__·import·annotations
 3 from·enum·import·Enum
3 import·copyreg4 import·copyreg
4 from·.pretty·import·pretty5 from·.pretty·import·pretty
5 from·typing·import·Any,·Iterator,·Hashable,·Pattern,·Iterable,·Mapping6 from·typing·import·Any,·Iterator,·Pattern,·Iterable,·Mapping,·TypeVar,·overload
  
6 __all__·=·(7 __all__·=·(
7 ····'Selector',8 ····'Selector',
8 ····'SelectorNull',9 ····'SelectorNull',
9 ····'SelectorTag',10 ····'SelectorTag',
10 ····'SelectorAttribute',11 ····'SelectorAttribute',
11 ····'SelectorContains',12 ····'SelectorContains',
12 ····'SelectorNth',13 ····'SelectorNth',
13 ····'SelectorLang',14 ····'SelectorLang',
14 ····'SelectorList',15 ····'SelectorList',
15 ····'Namespaces',16 ····'Namespaces',
16 ····'CustomSelectors'17 ····'CustomSelectors'
17 )18 )
  
  
18 SEL_EMPTY·=·0x119 SEL_EMPTY·=·0x1
19 SEL_ROOT·=·0x220 SEL_ROOT·=·0x2
20 SEL_DEFAULT·=·0x421 SEL_DEFAULT·=·0x4
21 SEL_INDETERMINATE·=·0x822 SEL_INDETERMINATE·=·0x8
22 SEL_SCOPE·=·0x1023 SEL_SCOPE·=·0x10
23 SEL_DIR_LTR·=·0x2024 SEL_DIR_LTR·=·0x20
24 SEL_DIR_RTL·=·0x4025 SEL_DIR_RTL·=·0x40
25 SEL_IN_RANGE·=·0x8026 SEL_IN_RANGE·=·0x80
26 SEL_OUT_OF_RANGE·=·0x10027 SEL_OUT_OF_RANGE·=·0x100
27 SEL_DEFINED·=·0x20028 SEL_DEFINED·=·0x200
28 SEL_PLACEHOLDER_SHOWN·=·0x40029 SEL_PLACEHOLDER_SHOWN·=·0x400
  
  
 30 def·_repr_expand(value:·Any)·->·bool:··#·pragma:·no·cover
 31 ····"""Check·if·the·value·is·an·immutable·object·that·uses·the·default·representation."""
  
 32 ····return·isinstance(value,·Immutable)·and·type(value).__repr__·is·Immutable.__repr__
  
  
 33 def·_repr_value(value:·Any)·->·Any:··#·pragma:·no·cover
 34 ····"""
 35 ····Return·the·representation·of·a·leaf·value,·or·the·value·itself·if·it·must·be·expanded.
  
 36 ····Immutable·objects·using·the·default·representation·are·expanded,·as·are·tuples·containing·them.
 37 ····"""
  
 38 ····if·_repr_expand(value)·or·(value.__class__·is·tuple·and·any(_repr_expand(v)·for·v·in·value)):
 39 ········return·value
 40 ····return·repr(value)
  
  
29 class·Immutable:41 class·Immutable:
30 ····"""Immutable."""42 ····"""Immutable."""
  
31 ····__slots__:·tuple[str,·...]·=·('_hash',)43 ····__slots__:·tuple[str,·...]·=·('_hash',)
  
32 ····_hash:·int44 ····_hash:·int
  
Offset 51, 139 lines modifiedOffset 69, 100 lines modified
51 ····@classmethod69 ····@classmethod
52 ····def·__base__(cls)·->·type[Immutable]:70 ····def·__base__(cls)·->·type[Immutable]:
53 ········"""Get·base·class."""71 ········"""Get·base·class."""
  
54 ········return·cls72 ········return·cls
  
55 ····def·__eq__(self,·other:·Any)·->·bool:73 ····def·__eq__(self,·other:·Any)·->·bool:
56 ········"""Equal."""74 ········"""Check·equaling·in·a·non-recursive·manner."""
  
 75 ········stack:·list[tuple[Immutable,·Any]]·=·[(self,·other)]
 76 ········while·stack:
 77 ············a,·b·=·stack.pop()
 78 ············if·a·is·b:
 79 ················continue
  
 80 ············#·The·hash·is·derived·from·the·content,·so·differing·hashes·cannot·be·equal.
 81 ············if·not·isinstance(b,·a.__base__())·or·a._hash·!=·b._hash:
 82 ················return·False
  
 83 ············#·Compare·the·attributes·in·the·slot
 84 ············for·key·in·a.__slots__[:-1]:
 85 ················x·=·getattr(a,·key)
 86 ················y·=·getattr(b,·key)
 87 ················if·isinstance(x,·Immutable):
 88 ····················stack.append((x,·y))
 89 ················elif·x.__class__·is·tuple·and·y.__class__·is·tuple:
 90 ····················if·len(x)·!=·len(y):··#·pragma:·no·cover
 91 ························return·False
 92 ····················for·i,·j·in·zip(x,·y,·strict=True):
 93 ························if·isinstance(i,·Immutable):
 94 ····························stack.append((i,·j))
 95 ························elif·i·!=·j:··#·pragma:·no·cover
 96 ····························return·False
 97 ················elif·x·!=·y:
 98 ····················return·False
57 ········return·(99 ········return·True
58 ············isinstance(other,·self.__base__())·and 
59 ············all(getattr(other,·key)·==·getattr(self,·key)·for·key·in·self.__slots__·if·key·!=·'_hash') 
60 ········) 
  
61 ····def·__ne__(self,·other:·Any)·->·bool:100 ····def·__ne__(self,·other:·Any)·->·bool:
62 ········"""Equal."""101 ········"""Not·equal."""
  
 102 ········return·not·self.__eq__(other)
63 ········return·( 
64 ············not·isinstance(other,·self.__base__())·or 
65 ············any(getattr(other,·key)·!=·getattr(self,·key)·for·key·in·self.__slots__·if·key·!=·'_hash') 
66 ········) 
  
67 ····def·__hash__(self)·->·int:103 ····def·__hash__(self)·->·int:
68 ········"""Hash."""104 ········"""Hash."""
  
69 ········return·self._hash105 ········return·self._hash
  
70 ····def·__setattr__(self,·name:·str,·value:·Any)·->·None:106 ····def·__setattr__(self,·name:·str,·value:·Any)·->·None:
71 ········"""Prevent·mutability."""107 ········"""Prevent·mutability."""
  
72 ········raise·AttributeError(f"'{self.__class__.__name__}'·is·immutable")108 ········raise·AttributeError(f"'{self.__class__.__name__}'·is·immutable")
  
73 ····def·__repr__(self)·->·str:··#·pragma:·no·cover109 ····def·__repr__(self)·->·str:··#·pragma:·no·cover
74 ········"""Representation."""110 ········"""
 111 ········Build·a·representation·without·using·recursion.
  
75 ········r·=·',·'.join([f"{k}={getattr(self,·k)!r}"·for·k·in·self.__slots__[:-1]]) 
76 ········return·f"{self.__class__.__name__}({r})"112 ········Selectors·can·be·nested·very·deeply,·so·build·the·representation·of·nested
 113 ········immutable·objects·with·an·explicit·stack·instead·of·recursing·into·their·`__repr__`.
 114 ········Strings·on·the·stack·are·output·as·is,·other·items·are·expanded·into·more·items.
Max diff block lines reached; 11400/16816 bytes (67.79%) of diff not shown.
⊟
959 B
soupsieve/util.py
    
Offset 2, 14 lines modifiedOffset 2, 16 lines modified
2 from·__future__·import·annotations2 from·__future__·import·annotations
3 from·functools·import·wraps,·lru_cache3 from·functools·import·wraps,·lru_cache
4 import·warnings4 import·warnings
5 import·re5 import·re
6 from·typing·import·Callable,·Any6 from·typing·import·Callable,·Any
  
7 DEBUG·=·0x000017 DEBUG·=·0x00001
 8 NOCACHE·=·0x00002
 9 NOSTRICT·=·0x00004
  
8 RE_PATTERN_LINE_SPLIT·=·re.compile(r'(?:\r\n|(?!\r\n)[\n\r])|$')10 RE_PATTERN_LINE_SPLIT·=·re.compile(r'(?:\r\n|(?!\r\n)[\n\r])|$')
  
9 UC_A·=·ord('A')11 UC_A·=·ord('A')
10 UC_Z·=·ord('Z')12 UC_Z·=·ord('Z')
  
  
Offset 78, 17 lines modifiedOffset 80, 17 lines modified
  
78 def·get_pattern_context(pattern:·str,·index:·int)·->·tuple[str,·int,·int]:80 def·get_pattern_context(pattern:·str,·index:·int)·->·tuple[str,·int,·int]:
79 ····"""Get·the·pattern·context."""81 ····"""Get·the·pattern·context."""
  
80 ····last·=·082 ····last·=·0
81 ····current_line·=·183 ····current_line·=·1
82 ····col·=·184 ····col·=·1
83 ····text·=·[]··#·type:·list[str]85 ····text:·list[str]·=·[]
84 ····line·=·186 ····line·=·1
85 ····offset·=·None··#·type:·int·|·None87 ····offset:·int·|·None·=·None
  
86 ····#·Split·pattern·by·newline·and·handle·the·text·before·the·newline88 ····#·Split·pattern·by·newline·and·handle·the·text·before·the·newline
87 ····for·m·in·RE_PATTERN_LINE_SPLIT.finditer(pattern):89 ····for·m·in·RE_PATTERN_LINE_SPLIT.finditer(pattern):
88 ········linetext·=·pattern[last:m.start(0)]90 ········linetext·=·pattern[last:m.start(0)]
89 ········if·not·len(m.group(0))·and·not·len(text):91 ········if·not·len(m.group(0))·and·not·len(text):
90 ············indent·=·''92 ············indent·=·''
91 ············offset·=·-193 ············offset·=·-1
⊟
3.31 KB
svglib/__init__.py
    
Offset 24, 15 lines modifiedOffset 24, 19 lines modified
  
24 try:24 try:
25 ····__version__·=·version("svglib")25 ····__version__·=·version("svglib")
26 except·PackageNotFoundError:26 except·PackageNotFoundError:
27 ····__version__·=·"unknown"27 ····__version__·=·"unknown"
  
  
28 def·svg2pdf(path:·str,·outputPat:·Optional[str]·=·None)·->·None:28 def·svg2pdf(
 29 ····path:·str,
 30 ····outputPat:·Optional[str]·=·None,
 31 ····external_reference_root:·Optional[str]·=·None,
 32 )·->·None:
29 ····"""Convert·an·SVG·file·to·PDF·format.33 ····"""Convert·an·SVG·file·to·PDF·format.
  
30 ····High-level·function·that·loads·an·SVG·file,·converts·it·to·a·ReportLab·drawing,34 ····High-level·function·that·loads·an·SVG·file,·converts·it·to·a·ReportLab·drawing,
31 ····and·saves·it·as·a·PDF·file.·Supports·both·.svg·and·.svgz·(compressed·SVG)·files.35 ····and·saves·it·as·a·PDF·file.·Supports·both·.svg·and·.svgz·(compressed·SVG)·files.
  
32 ····Args:36 ····Args:
33 ········path:·Path·to·the·input·SVG·file·(.svg·or·.svgz·extension).37 ········path:·Path·to·the·input·SVG·file·(.svg·or·.svgz·extension).
Offset 40, 14 lines modifiedOffset 44, 17 lines modified
40 ············-·%(dirname)s:·Directory·of·input·file44 ············-·%(dirname)s:·Directory·of·input·file
41 ············-·%(basename)s:·Full·filename·with·extension45 ············-·%(basename)s:·Full·filename·with·extension
42 ············-·%(base)s:·Filename·without·extension46 ············-·%(base)s:·Filename·without·extension
43 ············-·%(ext)s:·File·extension47 ············-·%(ext)s:·File·extension
44 ············-·%(now)s:·Current·datetime·object48 ············-·%(now)s:·Current·datetime·object
45 ············-·%(format)s:·Output·format·(always·"pdf")49 ············-·%(format)s:·Output·format·(always·"pdf")
46 ············Also·supports·{name}·format·strings.50 ············Also·supports·{name}·format·strings.
 51 ········external_reference_root:·Optional·directory·that·external·<image>/<use>
 52 ············references·must·resolve·inside.·None·(the·default)·keeps·the
 53 ············library's·behaviour·of·allowing·any·relative·reference.
  
47 ····Returns:54 ····Returns:
48 ········None.·The·PDF·file·is·written·to·disk.55 ········None.·The·PDF·file·is·written·to·disk.
  
49 ····Raises:56 ····Raises:
50 ········FileNotFoundError:·If·the·input·SVG·file·does·not·exist.57 ········FileNotFoundError:·If·the·input·SVG·file·does·not·exist.
51 ········Exception:·If·SVG·parsing·or·PDF·generation·fails.58 ········Exception:·If·SVG·parsing·or·PDF·generation·fails.
Offset 85, 15 lines modifiedOffset 92, 15 lines modified
85 ····#·allow·classic·%%(name)s·notation92 ····#·allow·classic·%%(name)s·notation
86 ····out_path·=·out_pattern·%·file_info93 ····out_path·=·out_pattern·%·file_info
87 ····#·allow·also·newer·{name}·notation94 ····#·allow·also·newer·{name}·notation
88 ····out_path·=·out_path.format(**file_info)95 ····out_path·=·out_path.format(**file_info)
  
89 ····#·generate·a·drawing·from·the·SVG·file96 ····#·generate·a·drawing·from·the·SVG·file
90 ····try:97 ····try:
91 ········drawing·=·svglib.svg2rlg(path)98 ········drawing·=·svglib.svg2rlg(path,·external_reference_root=external_reference_root)
92 ····except:99 ····except:
93 ········print("Rendering·failed.")100 ········print("Rendering·failed.")
94 ········raise101 ········raise
  
95 ····#·save·converted·file102 ····#·save·converted·file
96 ····if·drawing:103 ····if·drawing:
97 ········renderPDF.drawToFile(drawing,·out_path,·showBoundary=0)104 ········renderPDF.drawToFile(drawing,·out_path,·showBoundary=0)
Offset 155, 14 lines modifiedOffset 162, 24 lines modified
155 ········"--output",162 ········"--output",
156 ········metavar="PATH_PAT",163 ········metavar="PATH_PAT",
157 ········help="Set·output·path·(incl.·the·placeholders:·dirname,·basename,"164 ········help="Set·output·path·(incl.·the·placeholders:·dirname,·basename,"
158 ········"base,·ext,·now)·in·both,·%%(name)s·and·{name}·notations.",165 ········"base,·ext,·now)·in·both,·%%(name)s·and·{name}·notations.",
159 ····)166 ····)
  
160 ····p.add_argument(167 ····p.add_argument(
 168 ········"-R",
 169 ········"--external-root",
 170 ········metavar="DIR",
 171 ········help="Directory·that·external·image/use·references·must·stay·inside.·"
 172 ········"Defaults·to·the·input·file's·own·directory,·so·a·converted·SVG·"
 173 ········"cannot·read·files·elsewhere·on·disk.·Pass·a·parent·directory·to·"
 174 ········"allow·shared·assets,·or·/·to·allow·any·relative·reference.",
 175 ····)
  
 176 ····p.add_argument(
161 ········"input",177 ········"input",
162 ········metavar="PATH",178 ········metavar="PATH",
163 ········nargs="*",179 ········nargs="*",
164 ········help="Input·SVG·file·path·with·extension·.svg·or·.svgz.",180 ········help="Input·SVG·file·path·with·extension·.svg·or·.svgz.",
165 ····)181 ····)
  
166 ····args·=·p.parse_args()182 ····args·=·p.parse_args()
Offset 173, 8 lines modifiedOffset 190, 12 lines modified
  
173 ····if·not·args.input:190 ····if·not·args.input:
174 ········p.print_usage()191 ········p.print_usage()
175 ········sys.exit()192 ········sys.exit()
  
176 ····paths·=·[a·for·a·in·args.input·if·exists(a)]193 ····paths·=·[a·for·a·in·args.input·if·exists(a)]
177 ····for·path·in·paths:194 ····for·path·in·paths:
178 ········svg2pdf(path,·outputPat=args.output)195 ········#·Command-line·input·is·routinely·untrusted·(a·downloaded·or·uploaded
 196 ········#·file),·so·confine·external·references·to·the·document's·own·directory
 197 ········#·unless·the·caller·widens·the·root·explicitly.
 198 ········root·=·args.external_root·or·dirname(path)·or·"."
 199 ········svg2pdf(path,·outputPat=args.output,·external_reference_root=root)
⊟
4.22 KB
svglib/fonts.py
    
Offset 11, 15 lines modifiedOffset 11, 15 lines modified
11 -·Automatic·font·file·detection·and·registration11 -·Automatic·font·file·detection·and·registration
12 """12 """
  
13 import·os13 import·os
14 import·shutil14 import·shutil
15 import·subprocess15 import·subprocess
16 import·sys16 import·sys
17 from·typing·import·Dict,·Optional,·Tuple,·Union17 from·typing·import·Optional,·Union
  
18 from·reportlab.pdfbase.pdfmetrics·import·registerFont18 from·reportlab.pdfbase.pdfmetrics·import·registerFont
19 from·reportlab.pdfbase.ttfonts·import·TTFError,·TTFont19 from·reportlab.pdfbase.ttfonts·import·TTFError,·TTFont
  
20 STANDARD_FONT_NAMES·=·(20 STANDARD_FONT_NAMES·=·(
21 ····"Times-Roman",21 ····"Times-Roman",
22 ····"Times-Italic",22 ····"Times-Italic",
Offset 67, 16 lines modifiedOffset 67, 16 lines modified
67 ················'rlgFont':·'reportlab_font_name',67 ················'rlgFont':·'reportlab_font_name',
68 ················'exact':·True/False68 ················'exact':·True/False
69 ············}69 ············}
  
70 ········Internal·names·are·normalized·for·efficient·lookup·and·follow·the·pattern:70 ········Internal·names·are·normalized·for·efficient·lookup·and·follow·the·pattern:
71 ········'Family-WeightStyle'·(e.g.,·'Arial-BoldItalic').71 ········'Family-WeightStyle'·(e.g.,·'Arial-BoldItalic').
72 ········"""72 ········"""
73 ········self._map:·Dict[str,·Dict[str,·Union[str,·bool,·int]]]·=·{}73 ········self._map:·dict[str,·dict[str,·Union[str,·bool,·int]]]·=·{}
74 ········self._family_index:·Dict[str,·str]·=·{}··#·lowercase·family·→·canonical·family74 ········self._family_index:·dict[str,·str]·=·{}··#·lowercase·family·→·canonical·family
  
75 ········self.register_default_fonts()75 ········self.register_default_fonts()
  
76 ····@staticmethod76 ····@staticmethod
77 ····def·build_internal_name(77 ····def·build_internal_name(
78 ········family:·str,·weight:·str·=·"normal",·style:·str·=·"normal"78 ········family:·str,·weight:·str·=·"normal",·style:·str·=·"normal"
79 ····)·->·str:79 ····)·->·str:
Offset 150, 15 lines modifiedOffset 150, 15 lines modified
150 ········elif·not·is_bold·and·is_italic:150 ········elif·not·is_bold·and·is_italic:
151 ············prefix·=·"i"151 ············prefix·=·"i"
152 ········filename·=·f"{basename}{prefix}.{extension}"152 ········filename·=·f"{basename}{prefix}.{extension}"
153 ········return·filename153 ········return·filename
  
154 ····def·use_fontconfig(154 ····def·use_fontconfig(
155 ········self,·font_name:·str,·weight:·str·=·"normal",·style:·str·=·"normal"155 ········self,·font_name:·str,·weight:·str·=·"normal",·style:·str·=·"normal"
156 ····)·->·Tuple[Optional[str],·bool]:156 ····)·->·tuple[Optional[str],·bool]:
157 ········"""Find·and·register·a·font·using·system·fontconfig.157 ········"""Find·and·register·a·font·using·system·fontconfig.
  
158 ········Uses·the·system's·fontconfig·utility·to·locate·and·register·fonts·that158 ········Uses·the·system's·fontconfig·utility·to·locate·and·register·fonts·that
159 ········match·the·given·specifications.·This·provides·access·to·system-installed159 ········match·the·given·specifications.·This·provides·access·to·system-installed
160 ········fonts·that·aren't·part·of·the·standard·PDF·font·set.160 ········fonts·that·aren't·part·of·the·standard·PDF·font·set.
  
161 ········Args:161 ········Args:
Offset 348, 15 lines modifiedOffset 348, 15 lines modified
348 ····def·register_font(348 ····def·register_font(
349 ········self,349 ········self,
350 ········font_family:·str,350 ········font_family:·str,
351 ········font_path:·Optional[str]·=·None,351 ········font_path:·Optional[str]·=·None,
352 ········weight:·str·=·"normal",352 ········weight:·str·=·"normal",
353 ········style:·str·=·"normal",353 ········style:·str·=·"normal",
354 ········rlgFontName:·Optional[str]·=·None,354 ········rlgFontName:·Optional[str]·=·None,
355 ····)·->·Tuple[Optional[str],·bool]:355 ····)·->·tuple[Optional[str],·bool]:
356 ········"""Register·a·font·or·create·a·mapping·to·a·ReportLab·font·name.356 ········"""Register·a·font·or·create·a·mapping·to·a·ReportLab·font·name.
  
357 ········This·method·handles·two·scenarios:357 ········This·method·handles·two·scenarios:
358 ········1.·Registering·a·custom·TrueType·font·file·with·ReportLab358 ········1.·Registering·a·custom·TrueType·font·file·with·ReportLab
359 ········2.·Creating·a·mapping·from·SVG·font·specifications·to·existing·ReportLab·fonts359 ········2.·Creating·a·mapping·from·SVG·font·specifications·to·existing·ReportLab·fonts
  
360 ········For·standard·PDF·fonts,·only·the·mapping·is·created.·For·custom·fonts,360 ········For·standard·PDF·fonts,·only·the·mapping·is·created.·For·custom·fonts,
Offset 422, 15 lines modifiedOffset 422, 15 lines modified
422 ················return·NOT_FOUND422 ················return·NOT_FOUND
  
423 ········#·If·we·reach·here,·no·registration·was·possible423 ········#·If·we·reach·here,·no·registration·was·possible
424 ········return·NOT_FOUND424 ········return·NOT_FOUND
  
425 ····def·find_font(425 ····def·find_font(
426 ········self,·font_name:·str,·weight:·str·=·"normal",·style:·str·=·"normal"426 ········self,·font_name:·str,·weight:·str·=·"normal",·style:·str·=·"normal"
427 ····)·->·Tuple[str,·bool]:427 ····)·->·tuple[str,·bool]:
428 ········"""Find·the·best·matching·ReportLab·font·for·given·specifications.428 ········"""Find·the·best·matching·ReportLab·font·for·given·specifications.
  
429 ········Searches·through·the·font·registry·to·find·the·most·appropriate·font·match.429 ········Searches·through·the·font·registry·to·find·the·most·appropriate·font·match.
430 ········Uses·a·multi-step·fallback·strategy:·exact·match,·standard·fonts,·file-based430 ········Uses·a·multi-step·fallback·strategy:·exact·match,·standard·fonts,·file-based
431 ········registration,·fontconfig·discovery,·and·finally·default·fallback.431 ········registration,·fontconfig·discovery,·and·finally·default·fallback.
  
432 ········Args:432 ········Args:
Offset 476, 15 lines modifiedOffset 476, 15 lines modified
  
476 def·register_font(476 def·register_font(
477 ····font_name:·str,477 ····font_name:·str,
478 ····font_path:·Optional[str]·=·None,478 ····font_path:·Optional[str]·=·None,
479 ····weight:·str·=·"normal",479 ····weight:·str·=·"normal",
480 ····style:·str·=·"normal",480 ····style:·str·=·"normal",
481 ····rlgFontName:·Optional[str]·=·None,481 ····rlgFontName:·Optional[str]·=·None,
482 )·->·Tuple[Optional[str],·bool]:482 )·->·tuple[Optional[str],·bool]:
483 ····"""Register·a·font·with·the·global·font·map.483 ····"""Register·a·font·with·the·global·font·map.
  
484 ····Convenience·function·that·delegates·to·the·global·FontMap·instance.484 ····Convenience·function·that·delegates·to·the·global·FontMap·instance.
485 ····Registers·a·custom·font·or·creates·a·mapping·to·an·existing·ReportLab·font.485 ····Registers·a·custom·font·or·creates·a·mapping·to·an·existing·ReportLab·font.
  
486 ····Args:486 ····Args:
487 ········font_name:·SVG·font·family·name·(e.g.,·"Arial",·"Times·New·Roman").487 ········font_name:·SVG·font·family·name·(e.g.,·"Arial",·"Times·New·Roman").
Offset 501, 15 lines modifiedOffset 501, 15 lines modified
501 ········FontMap.register_font:·The·underlying·implementation·method.501 ········FontMap.register_font:·The·underlying·implementation·method.
502 ····"""502 ····"""
503 ····return·_font_map.register_font(font_name,·font_path,·weight,·style,·rlgFontName)503 ····return·_font_map.register_font(font_name,·font_path,·weight,·style,·rlgFontName)
  
  
504 def·find_font(504 def·find_font(
505 ····font_name:·str,·weight:·str·=·"normal",·style:·str·=·"normal"505 ····font_name:·str,·weight:·str·=·"normal",·style:·str·=·"normal"
506 )·->·Tuple[str,·bool]:506 )·->·tuple[str,·bool]:
507 ····"""Find·the·best·matching·font·from·the·global·font·registry.507 ····"""Find·the·best·matching·font·from·the·global·font·registry.
  
508 ····Convenience·function·that·delegates·to·the·global·FontMap·instance.508 ····Convenience·function·that·delegates·to·the·global·FontMap·instance.
509 ····Searches·for·fonts·using·a·multi-step·fallback·strategy.509 ····Searches·for·fonts·using·a·multi-step·fallback·strategy.
  
510 ····Args:510 ····Args:
511 ········font_name:·SVG·font·family·name·to·search·for.511 ········font_name:·SVG·font·family·name·to·search·for.
⊟
76.5 KB
svglib/svglib.py
    
Offset 18, 40 lines modifiedOffset 18, 48 lines modified
18 ········$·python·-m·svglib·foo.svg18 ········$·python·-m·svglib·foo.svg
19 """19 """
  
20 import·base6420 import·base64
21 import·copy21 import·copy
22 import·gzip22 import·gzip
23 import·itertools23 import·itertools
24 import·locale 
25 import·logging24 import·logging
26 import·os25 import·os
27 import·pathlib26 import·pathlib
28 import·re27 import·re
29 import·shlex28 import·shlex
30 import·shutil29 import·shutil
31 import·sys 
32 from·collections·import·defaultdict,·namedtuple30 from·collections·import·defaultdict,·namedtuple
33 from·io·import·BytesIO31 from·io·import·BytesIO
34 from·typing·import·Any,·BinaryIO,·Dict,·List,·Optional,·TextIO,·Tuple,·Union32 from·typing·import·(
 33 ····Any,
 34 ····BinaryIO,
 35 ····Optional,
 36 ····TextIO,
 37 ····TypedDict,
 38 ····Union,
 39 ····cast,
 40 )
  
35 from·PIL·import·Image·as·PILImage41 from·PIL·import·Image·as·PILImage
 42 from·reportlab.graphics.renderSVG·import·SVGCanvas
36 from·reportlab.graphics.shapes·import·(43 from·reportlab.graphics.shapes·import·(
37 ····_CLOSEPATH,44 ····_CLOSEPATH,
38 ····Circle,45 ····Circle,
39 ····DirectDraw,46 ····DirectDraw,
40 ····Drawing,47 ····Drawing,
41 ····Ellipse,48 ····Ellipse,
42 ····Group,49 ····Group,
43 ····Image,50 ····Image,
44 ····Line,51 ····Line,
45 ····Path,52 ····Path,
46 ····Polygon,53 ····Polygon,
47 ····PolyLine,54 ····PolyLine,
48 ····Rect,55 ····Rect,
 56 ····Shape,
49 ····SolidShape,57 ····SolidShape,
50 ····String,58 ····String,
51 ····_renderPath,59 ····_renderPath,
52 )60 )
53 from·reportlab.lib·import·colors61 from·reportlab.lib·import·colors
54 from·reportlab.lib.units·import·toLength62 from·reportlab.lib.units·import·toLength
55 from·reportlab.pdfbase.pdfmetrics·import·stringWidth63 from·reportlab.pdfbase.pdfmetrics·import·stringWidth
Offset 89, 14 lines modifiedOffset 97, 48 lines modified
89 ····convert_quadratic_to_cubic_path,97 ····convert_quadratic_to_cubic_path,
90 ····normalise_svg_path,98 ····normalise_svg_path,
91 )99 )
  
92 #·SVG·user·units·are·px;·ReportLab·works·in·points.··1·px·=·0.75·pt·(96·dpi·/·72·dpi).100 #·SVG·user·units·are·px;·ReportLab·works·in·points.··1·px·=·0.75·pt·(96·dpi·/·72·dpi).
93 PX_TO_PT·=·0.75101 PX_TO_PT·=·0.75
  
 102 #·An·SVG·source·accepted·by·the·public·API:·a·path,·a·path-like·object,·or·an
 103 #·already-open·binary/text·file·object.
 104 SVGSource·=·Union[str,·os.PathLike[str],·BinaryIO,·TextIO]
  
 105 #·A·single·gradient·stop:·(offset,·ReportLab·color).·The·color·is·untyped
 106 #·because·ReportLab·ships·no·stubs.
 107 GradientStop·=·tuple[float,·Any]
  
  
 108 class·_GradientDefBase(TypedDict):
 109 ····"""Keys·always·present·on·a·parsed·gradient·definition."""
  
 110 ····type:·str··#·"linear"·or·"radial"
 111 ····gradientUnits:·str
 112 ····spreadMethod:·str
 113 ····stops:·list[GradientStop]
 114 ····href:·Optional[str]
  
  
 115 class·_GradientDef(_GradientDefBase,·total=False):
 116 ····"""Geometry·keys·present·depending·on·``type``·(linear·vs·radial)."""
  
 117 ····#·linearGradient
 118 ····x1:·float
 119 ····y1:·float
 120 ····x2:·float
 121 ····y2:·float
 122 ····#·radialGradient
 123 ····cx:·float
 124 ····cy:·float
 125 ····r:·float
 126 ····fx:·float
 127 ····fy:·float
  
  
94 def·_convert_palette_to_rgba(image:·PILImage.Image)·->·PILImage.Image:128 def·_convert_palette_to_rgba(image:·PILImage.Image)·->·PILImage.Image:
95 ····"""Convert·a·palette-based·image·with·transparency·to·RGBA·format.129 ····"""Convert·a·palette-based·image·with·transparency·to·RGBA·format.
  
96 ····This·function·checks·if·a·PIL·Image·is·in·palette·mode·('P')·and·has130 ····This·function·checks·if·a·PIL·Image·is·in·palette·mode·('P')·and·has
97 ····transparency·information.·If·so,·it·converts·the·image·to·RGBA·to·prevent131 ····transparency·information.·If·so,·it·converts·the·image·to·RGBA·to·prevent
98 ····potential·warnings·or·errors·during·processing.132 ····potential·warnings·or·errors·during·processing.
Offset 116, 15 lines modifiedOffset 158, 15 lines modified
  
116 def·register_font(158 def·register_font(
117 ····font_name:·str,159 ····font_name:·str,
118 ····font_path:·Optional[str]·=·None,160 ····font_path:·Optional[str]·=·None,
119 ····weight:·str·=·"normal",161 ····weight:·str·=·"normal",
120 ····style:·str·=·"normal",162 ····style:·str·=·"normal",
121 ····rlgFontName:·Optional[str]·=·None,163 ····rlgFontName:·Optional[str]·=·None,
122 )·->·Tuple[Optional[str],·bool]:164 )·->·tuple[Optional[str],·bool]:
123 ····"""Register·a·font·for·use·in·SVG·processing.165 ····"""Register·a·font·for·use·in·SVG·processing.
  
124 ····This·function·serves·as·a·backward-compatible·wrapper·for·the·font166 ····This·function·serves·as·a·backward-compatible·wrapper·for·the·font
125 ····registration·logic·defined·in·the·`svglib.fonts`·module.167 ····registration·logic·defined·in·the·`svglib.fonts`·module.
  
126 ····Args:168 ····Args:
127 ········font_name:·The·name·of·the·font·to·register.169 ········font_name:·The·name·of·the·font·to·register.
Offset 138, 15 lines modifiedOffset 180, 15 lines modified
138 ········if·the·registration·was·successful.180 ········if·the·registration·was·successful.
139 ····"""181 ····"""
140 ····return·_fonts_register_font(font_name,·font_path,·weight,·style,·rlgFontName)182 ····return·_fonts_register_font(font_name,·font_path,·weight,·style,·rlgFontName)
  
  
141 def·find_font(183 def·find_font(
142 ····font_name:·str,·weight:·str·=·"normal",·style:·str·=·"normal"184 ····font_name:·str,·weight:·str·=·"normal",·style:·str·=·"normal"
143 )·->·Tuple[str,·bool]:185 )·->·tuple[str,·bool]:
144 ····"""Find·a·registered·font·by·its·properties.186 ····"""Find·a·registered·font·by·its·properties.
  
145 ····This·function·serves·as·a·backward-compatible·wrapper·for·the·font187 ····This·function·serves·as·a·backward-compatible·wrapper·for·the·font
Max diff block lines reached; 74929/78348 bytes (95.64%) of diff not shown.
⊟
6.57 KB
svglib/utils.py
    
Offset 11, 20 lines modifiedOffset 11, 20 lines modified
11 -·Elliptical·arc·processing·functions11 -·Elliptical·arc·processing·functions
12 -·Vector·mathematics·helpers12 -·Vector·mathematics·helpers
13 -·String·parsing·utilities·for·SVG·attributes13 -·String·parsing·utilities·for·SVG·attributes
14 """14 """
  
15 import·re15 import·re
16 from·math·import·acos,·ceil,·copysign,·cos,·degrees,·fabs,·hypot,·radians,·sin,·sqrt16 from·math·import·acos,·ceil,·copysign,·cos,·degrees,·fabs,·hypot,·radians,·sin,·sqrt
17 from·typing·import·List,·Tuple,·Union,·cast17 from·typing·import·Union,·cast
  
18 from·reportlab.graphics.shapes·import·mmult,·rotate,·transformPoint,·translate18 from·reportlab.graphics.shapes·import·mmult,·rotate,·transformPoint,·translate
  
  
19 def·split_floats(op:·str,·min_num:·int,·value:·str)·->·List[Union[str,·List[float]]]:19 def·split_floats(op:·str,·min_num:·int,·value:·str)·->·list[Union[str,·list[float]]]:
20 ····"""Parse·SVG·coordinate·string·into·alternating·operators·and·coordinate·lists.20 ····"""Parse·SVG·coordinate·string·into·alternating·operators·and·coordinate·lists.
  
21 ····Splits·a·string·of·numeric·values·into·groups·and·pairs·each·group·with·the21 ····Splits·a·string·of·numeric·values·into·groups·and·pairs·each·group·with·the
22 ····appropriate·SVG·path·operation.·Automatically·converts·'M'·to·'L'·for·subsequent22 ····appropriate·SVG·path·operation.·Automatically·converts·'M'·to·'L'·for·subsequent
23 ····coordinate·pairs·to·handle·move-to·followed·by·line-to·sequences.23 ····coordinate·pairs·to·handle·move-to·followed·by·line-to·sequences.
  
24 ····Args:24 ····Args:
Offset 48, 23 lines modifiedOffset 48, 23 lines modified
48 ········whitespace·and·comma·separators·automatically.48 ········whitespace·and·comma·separators·automatically.
49 ····"""49 ····"""
50 ····floats·=·[50 ····floats·=·[
51 ········float(seq)51 ········float(seq)
52 ········for·seq·in·re.findall(r"(-?\d*\.?\d*(?:[eE][+-]?\d+)?)",·value)52 ········for·seq·in·re.findall(r"(-?\d*\.?\d*(?:[eE][+-]?\d+)?)",·value)
53 ········if·seq53 ········if·seq
54 ····]54 ····]
55 ····res:·List[Union[str,·List[float]]]·=·[]55 ····res:·list[Union[str,·list[float]]]·=·[]
56 ····for·i·in·range(0,·len(floats),·min_num):56 ····for·i·in·range(0,·len(floats),·min_num):
57 ········if·i·>·0·and·op·in·{"m",·"M"}:57 ········if·i·>·0·and·op·in·{"m",·"M"}:
58 ············op·=·"l"·if·op·==·"m"·else·"L"58 ············op·=·"l"·if·op·==·"m"·else·"L"
59 ········res.extend([op,·cast(List[float],·list(floats[i·:·i·+·min_num]))])59 ········res.extend([op,·cast(list[float],·list(floats[i·:·i·+·min_num]))])
60 ····return·res60 ····return·res
  
  
61 def·split_arc_values(op:·str,·value:·str)·->·List[Union[str,·List[float]]]:61 def·split_arc_values(op:·str,·value:·str)·->·list[Union[str,·list[float]]]:
62 ····"""Parse·SVG·elliptical·arc·parameters·into·structured·format.62 ····"""Parse·SVG·elliptical·arc·parameters·into·structured·format.
  
63 ····Parses·SVG·arc·command·parameters·which·consist·of:·rx,·ry,·x-axis-rotation,63 ····Parses·SVG·arc·command·parameters·which·consist·of:·rx,·ry,·x-axis-rotation,
64 ····large-arc-flag,·sweep-flag,·x,·y.·Each·complete·parameter·set·is·paired·with64 ····large-arc-flag,·sweep-flag,·x,·y.·Each·complete·parameter·set·is·paired·with
65 ····the·operation·character.65 ····the·operation·character.
  
66 ····Args:66 ····Args:
Offset 93, 21 lines modifiedOffset 93, 21 lines modified
93 ····#·3·numb,·2·flags,·1·coord·pair93 ····#·3·numb,·2·flags,·1·coord·pair
94 ····a_seq_re·=·(94 ····a_seq_re·=·(
95 ········r"[\s,]*".join(95 ········r"[\s,]*".join(
96 ············[float_re,·float_re,·float_re,·flag_re,·flag_re,·float_re,·float_re]96 ············[float_re,·float_re,·float_re,·flag_re,·flag_re,·float_re,·float_re]
97 ········)97 ········)
98 ········+·r"[\s,]*"98 ········+·r"[\s,]*"
99 ····)99 ····)
100 ····res:·List[Union[str,·List[float]]]·=·[]100 ····res:·list[Union[str,·list[float]]]·=·[]
101 ····for·seq·in·re.finditer(a_seq_re,·value.strip()):101 ····for·seq·in·re.finditer(a_seq_re,·value.strip()):
102 ········res.extend([op,·cast(List[float],·list(float(num)·for·num·in·seq.groups()))])102 ········res.extend([op,·cast(list[float],·list(float(num)·for·num·in·seq.groups()))])
103 ····return·res103 ····return·res
  
  
104 def·normalise_svg_path(attr:·str)·->·List[Union[str,·List[float]]]:104 def·normalise_svg_path(attr:·str)·->·list[Union[str,·list[float]]]:
105 ····"""Normalize·SVG·path·data·into·structured·format.105 ····"""Normalize·SVG·path·data·into·structured·format.
  
106 ····Parses·raw·SVG·path·string·and·converts·it·into·a·standardized·list·format106 ····Parses·raw·SVG·path·string·and·converts·it·into·a·standardized·list·format
107 ····where·each·path·command·is·paired·with·its·coordinate·parameters.·Automatically107 ····where·each·path·command·is·paired·with·its·coordinate·parameters.·Automatically
108 ····handles·command·sequences·and·converts·implicit·line·commands·after·move·commands.108 ····handles·command·sequences·and·converts·implicit·line·commands·after·move·commands.
  
109 ····Args:109 ····Args:
Offset 154, 15 lines modifiedOffset 154, 15 lines modified
154 ········"C":·6,154 ········"C":·6,
155 ········"c":·6,155 ········"c":·6,
156 ········"Z":·0,156 ········"Z":·0,
157 ········"z":·0,157 ········"z":·0,
158 ····}158 ····}
159 ····op_keys·=·ops.keys()159 ····op_keys·=·ops.keys()
  
160 ····result:·List[Union[str,·List[float]]]·=·[]160 ····result:·list[Union[str,·list[float]]]·=·[]
161 ····groups·=·re.split("([achlmqstvz])",·attr.strip(),·flags=re.I)161 ····groups·=·re.split("([achlmqstvz])",·attr.strip(),·flags=re.I)
162 ····op·=·""162 ····op·=·""
163 ····for·item·in·groups:163 ····for·item·in·groups:
164 ········if·item.strip()·==·"":164 ········if·item.strip()·==·"":
165 ············continue165 ············continue
166 ········if·item·in·op_keys:166 ········if·item·in·op_keys:
167 ············op·=·item167 ············op·=·item
Offset 175, 17 lines modifiedOffset 175, 17 lines modified
175 ················result.extend(split_floats(op,·ops[op],·item))175 ················result.extend(split_floats(op,·ops[op],·item))
176 ············op·=·cast(str,·result[-2])··#·Remember·last·op176 ············op·=·cast(str,·result[-2])··#·Remember·last·op
  
177 ····return·result177 ····return·result
  
  
178 def·convert_quadratic_to_cubic_path(178 def·convert_quadratic_to_cubic_path(
179 ····q0:·Tuple[float,·float],·q1:·Tuple[float,·float],·q2:·Tuple[float,·float]179 ····q0:·tuple[float,·float],·q1:·tuple[float,·float],·q2:·tuple[float,·float]
180 )·->·Tuple[180 )·->·tuple[
181 ····Tuple[float,·float],·Tuple[float,·float],·Tuple[float,·float],·Tuple[float,·float]181 ····tuple[float,·float],·tuple[float,·float],·tuple[float,·float],·tuple[float,·float]
182 ]:182 ]:
183 ····"""Convert·quadratic·Bezier·curve·to·cubic·Bezier·curve.183 ····"""Convert·quadratic·Bezier·curve·to·cubic·Bezier·curve.
  
184 ····Converts·a·quadratic·Bezier·curve·defined·by·control·points·q0,·q1,·q2184 ····Converts·a·quadratic·Bezier·curve·defined·by·control·points·q0,·q1,·q2
185 ····into·an·equivalent·cubic·Bezier·curve.·This·is·useful·for·SVG·processing185 ····into·an·equivalent·cubic·Bezier·curve.·This·is·useful·for·SVG·processing
186 ····since·cubic·curves·are·more·commonly·supported·than·quadratic·curves.186 ····since·cubic·curves·are·more·commonly·supported·than·quadratic·curves.
  
Offset 218, 15 lines modifiedOffset 218, 15 lines modified
  
  
218 #·***********************************************218 #·***********************************************
219 #·Helper·functions·for·elliptical·arc·conversion.219 #·Helper·functions·for·elliptical·arc·conversion.
220 #·***********************************************220 #·***********************************************
  
  
221 def·vector_angle(u:·Tuple[float,·float],·v:·Tuple[float,·float])·->·float:221 def·vector_angle(u:·tuple[float,·float],·v:·tuple[float,·float])·->·float:
222 ····"""Calculate·the·signed·angle·between·two·2D·vectors.222 ····"""Calculate·the·signed·angle·between·two·2D·vectors.
  
223 ····Computes·the·angle·between·vectors·u·and·v·using·the·atan2·method·to223 ····Computes·the·angle·between·vectors·u·and·v·using·the·atan2·method·to
224 ····determine·the·correct·quadrant·and·sign.·Returns·angle·in·degrees.224 ····determine·the·correct·quadrant·and·sign.·Returns·angle·in·degrees.
  
225 ····Args:225 ····Args:
226 ········u:·First·vector·as·(x,·y)·tuple.226 ········u:·First·vector·as·(x,·y)·tuple.
Offset 271, 15 lines modifiedOffset 271, 15 lines modified
271 ····x2:·float,271 ····x2:·float,
272 ····y2:·float,272 ····y2:·float,
273 ····fA:·int,273 ····fA:·int,
274 ····fS:·int,274 ····fS:·int,
275 ····rx:·float,275 ····rx:·float,
276 ····ry:·float,276 ····ry:·float,
277 ····phi:·float·=·0,277 ····phi:·float·=·0,
278 )·->·Tuple[float,·float,·float,·float,·float,·float]:278 )·->·tuple[float,·float,·float,·float,·float,·float]:
279 ····"""Convert·SVG·arc·endpoint·parameters·to·center-based·representation.279 ····"""Convert·SVG·arc·endpoint·parameters·to·center-based·representation.
  
Max diff block lines reached; 1432/6700 bytes (21.37%) of diff not shown.
⊟
11.0 KB
webencodings/__init__.py
    
Offset 1, 71 lines modifiedOffset 1, 74 lines modified
1 #·coding:·utf-8 
2 """1 """
  
3 ····webencodings2 ····webencodings
4 ····~~~~~~~~~~~~3 ····~~~~~~~~~~~~
  
5 ····This·is·a·Python·implementation·of·the·`WHATWG·Encoding·standard4 ····This·is·a·Python·implementation·of·the·`WHATWG·Encoding·standard
6 ····<http://encoding.spec.whatwg.org/>`.·See·README·for·details.5 ····<http://encoding.spec.whatwg.org/>`.·See·README·for·details.
  
7 ····:copyright:·Copyright·2012·by·Simon·Sapin6 ····:copyright:·Copyright·2012·by·Simon·Sapin
8 ····:license:·BSD,·see·LICENSE·for·details.7 ····:license:·BSD,·see·LICENSE·for·details.
  
9 """8 """
  
10 from·__future__·import·unicode_literals 
  
11 import·codecs9 import·codecs
  
 10 from·.custom·import·replacement_codec_info,·user_codec_info
12 from·.labels·import·LABELS11 from·.labels·import·LABELS
  
 12 VERSION·=·__version__·=·'0.6.1'
  
13 VERSION·=·'0.5.1' 
  
  
14 #·Some·names·in·Encoding·are·not·valid·Python·aliases.·Remap·these. 
15 PYTHON_NAMES·=·{13 PYTHON_NAMES·=·{
 14 ····#·Some·names·in·Encoding·are·not·valid·Python·aliases.·Remap·these:
16 ····'iso-8859-8-i':·'iso-8859-8',15 ····'iso-8859-8-i':·'iso8859-8',
17 ····'x-mac-cyrillic':·'mac-cyrillic',16 ····'x-mac-cyrillic':·'mac-cyrillic',
18 ····'macintosh':·'mac-roman',17 ····'macintosh':·'mac-roman',
19 ····'windows-874':·'cp874'}18 ····'windows-874':·'cp874',
 19 ····#·Some·WHATWG-defined·names·conflict·with·a·Python·alias·for·an
 20 ····#·incompatible·codec.·These·should·be·remapped·to·the·correct·one:
 21 ····'shift_jis':·'cp932',
 22 ····'big5':·'big5hkscs',
 23 ····'euc-kr':·'cp949',
 24 }
  
20 CACHE·=·{}25 CACHE·=·{}
  
  
21 def·ascii_lower(string):26 def·ascii_lower(string):
22 ····r"""Transform·(only)·ASCII·letters·to·lower·case:·A-Z·is·mapped·to·a-z.27 ····"""Transform·(only)·ASCII·letters·to·lower·case:·A-Z·is·mapped·to·a-z.
  
23 ····:param·string:·An·Unicode·string.28 ····:param·string:·An·Unicode·string.
24 ····:returns:·A·new·Unicode·string.29 ····:returns:·A·new·Unicode·string.
  
25 ····This·is·used·for·`ASCII·case-insensitive30 ····This·is·used·for·`ASCII·case-insensitive
26 ····<http://encoding.spec.whatwg.org/#ascii-case-insensitive>`_31 ····<http://encoding.spec.whatwg.org/#ascii-case-insensitive>`_
27 ····matching·of·encoding·labels.32 ····matching·of·encoding·labels.
28 ····The·same·matching·is·also·used,·among·other·things,33 ····The·same·matching·is·also·used,·among·other·things,
29 ····for·`CSS·keywords·<http://dev.w3.org/csswg/css-values/#keywords>`_.34 ····for·`CSS·keywords·<http://dev.w3.org/csswg/css-values/#keywords>`_.
  
30 ····This·is·different·from·the·:meth:`~py:str.lower`·method·of·Unicode·strings35 ····This·is·different·from·the·:meth:`str.lower`·method·of·Unicode·strings
31 ····which·also·affect·non-ASCII·characters,36 ····which·also·affect·non-ASCII·characters,
32 ····sometimes·mapping·them·into·the·ASCII·range:37 ····sometimes·mapping·them·into·the·ASCII·range:
  
33 ········>>>·keyword·=·u'Bac\N{KELVIN·SIGN}ground'38 ········>>>·keyword·=·'Bac\\N{KELVIN·SIGN}ground'
34 ········>>>·assert·keyword.lower()·==·u'background'39 ········>>>·assert·keyword.lower()·==·'background'
35 ········>>>·assert·ascii_lower(keyword)·!=·keyword.lower()40 ········>>>·assert·ascii_lower(keyword)·!=·keyword.lower()
36 ········>>>·assert·ascii_lower(keyword)·==·u'bac\N{KELVIN·SIGN}ground'41 ········>>>·assert·ascii_lower(keyword)·==·'bac\\N{KELVIN·SIGN}ground'
  
37 ····"""42 ····"""
38 ····#·This·turns·out·to·be·faster·than·unicode.translate()43 ····#·This·turns·out·to·be·faster·than·unicode.translate()
39 ····return·string.encode('utf8').lower().decode('utf8')44 ····return·string.encode().lower().decode()
  
  
40 def·lookup(label):45 def·lookup(label):
41 ····""" 
42 ····Look·for·an·encoding·by·its·label.46 ····"""Look·for·an·encoding·by·its·label.
  
43 ····This·is·the·spec’s·`get·an·encoding47 ····This·is·the·spec's·`get·an·encoding
44 ····<http://encoding.spec.whatwg.org/#concept-encoding-get>`_·algorithm.48 ····<http://encoding.spec.whatwg.org/#concept-encoding-get>`_·algorithm.
45 ····Supported·labels·are·listed·there.49 ····Supported·labels·are·listed·there.
  
46 ····:param·label:·A·string.50 ····:param·label:·A·string.
47 ····:returns:51 ····:returns:
48 ········An·:class:`Encoding`·object,·or·:obj:`None`·for·an·unknown·label.52 ········An·:class:`Encoding`·object,·or·:obj:`None`·for·an·unknown·label.
  
Offset 74, 45 lines modifiedOffset 77, 45 lines modified
74 ····label·=·ascii_lower(label.strip('\t\n\f\r·'))77 ····label·=·ascii_lower(label.strip('\t\n\f\r·'))
75 ····name·=·LABELS.get(label)78 ····name·=·LABELS.get(label)
76 ····if·name·is·None:79 ····if·name·is·None:
77 ········return·None80 ········return·None
78 ····encoding·=·CACHE.get(name)81 ····encoding·=·CACHE.get(name)
79 ····if·encoding·is·None:82 ····if·encoding·is·None:
80 ········if·name·==·'x-user-defined':83 ········if·name·==·'x-user-defined':
81 ············from·.x_user_defined·import·codec_info84 ············codec_info·=·user_codec_info
 85 ········elif·name·==·'replacement':
 86 ············codec_info·=·replacement_codec_info
82 ········else:87 ········else:
83 ············python_name·=·PYTHON_NAMES.get(name,·name)88 ············python_name·=·PYTHON_NAMES.get(name,·name)
84 ············#·Any·python_name·value·that·gets·to·here·should·be·valid.89 ············#·Any·python_name·value·that·gets·to·here·should·be·valid.
85 ············codec_info·=·codecs.lookup(python_name)90 ············codec_info·=·codecs.lookup(python_name)
86 ········encoding·=·Encoding(name,·codec_info)91 ········encoding·=·Encoding(name,·codec_info)
87 ········CACHE[name]·=·encoding92 ········CACHE[name]·=·encoding
88 ····return·encoding93 ····return·encoding
  
  
89 def·_get_encoding(encoding_or_label):94 def·_get_encoding(encoding_or_label):
90 ····""" 
91 ····Accept·either·an·encoding·object·or·label.95 ····"""Accept·either·an·encoding·object·or·label.
  
92 ····:param·encoding:·An·:class:`Encoding`·object·or·a·label·string.96 ····:param·encoding:·An·:class:`Encoding`·object·or·a·label·string.
93 ····:returns:·An·:class:`Encoding`·object.97 ····:returns:·An·:class:`Encoding`·object.
94 ····:raises:·:exc:`~exceptions.LookupError`·for·an·unknown·label.98 ····:raises:·:exc:`LookupError`·for·an·unknown·label.
  
95 ····"""99 ····"""
96 ····if·hasattr(encoding_or_label,·'codec_info'):100 ····if·hasattr(encoding_or_label,·'codec_info'):
97 ········return·encoding_or_label101 ········return·encoding_or_label
  
98 ····encoding·=·lookup(encoding_or_label)102 ····encoding·=·lookup(encoding_or_label)
99 ····if·encoding·is·None:103 ····if·encoding·is·None:
100 ········raise·LookupError('Unknown·encoding·label:·%r'·%·encoding_or_label)104 ········raise·LookupError(f'Unknown·encoding·label:·{encoding_or_label!r}')
101 ····return·encoding105 ····return·encoding
  
  
102 class·Encoding(object):106 class·Encoding:
103 ····"""Reresents·a·character·encoding·such·as·UTF-8, 
104 ····that·can·be·used·for·decoding·or·encoding.107 ····"""A·character·encoding·that·can·be·used·for·decoding·or·encoding.
  
105 ····..·attribute::·name108 ····..·attribute::·name
  
106 ········Canonical·name·of·the·encoding109 ········Canonical·name·of·the·encoding
  
Max diff block lines reached; 6493/11193 bytes (58.01%) of diff not shown.
⊟
45.0 B
encoding
    
Offset 1, 1 lines modifiedOffset 1, 1 lines modified
1 utf-81 us-ascii
⊟
3.3 KB
webencodings/labels.py
    
Offset 11, 16 lines modifiedOffset 11, 19 lines modified
11 """11 """
  
12 #·XXX·Do·not·edit!12 #·XXX·Do·not·edit!
13 #·This·file·is·automatically·generated·by·mklabels.py13 #·This·file·is·automatically·generated·by·mklabels.py
  
14 LABELS·=·{14 LABELS·=·{
15 ····'unicode-1-1-utf-8':···'utf-8',15 ····'unicode-1-1-utf-8':···'utf-8',
 16 ····'unicode11utf8':·······'utf-8',
 17 ····'unicode20utf8':·······'utf-8',
16 ····'utf-8':···············'utf-8',18 ····'utf-8':···············'utf-8',
17 ····'utf8':················'utf-8',19 ····'utf8':················'utf-8',
 20 ····'x-unicode20utf8':·····'utf-8',
18 ····'866':·················'ibm866',21 ····'866':·················'ibm866',
19 ····'cp866':···············'ibm866',22 ····'cp866':···············'ibm866',
20 ····'csibm866':············'ibm866',23 ····'csibm866':············'ibm866',
21 ····'ibm866':··············'ibm866',24 ····'ibm866':··············'ibm866',
22 ····'csisolatin2':·········'iso-8859-2',25 ····'csisolatin2':·········'iso-8859-2',
23 ····'iso-8859-2':··········'iso-8859-2',26 ····'iso-8859-2':··········'iso-8859-2',
24 ····'iso-ir-101':··········'iso-8859-2',27 ····'iso-ir-101':··········'iso-8859-2',
Offset 117, 14 lines modifiedOffset 120, 15 lines modified
117 ····'l9':··················'iso-8859-15',120 ····'l9':··················'iso-8859-15',
118 ····'iso-8859-16':·········'iso-8859-16',121 ····'iso-8859-16':·········'iso-8859-16',
119 ····'cskoi8r':·············'koi8-r',122 ····'cskoi8r':·············'koi8-r',
120 ····'koi':·················'koi8-r',123 ····'koi':·················'koi8-r',
121 ····'koi8':················'koi8-r',124 ····'koi8':················'koi8-r',
122 ····'koi8-r':··············'koi8-r',125 ····'koi8-r':··············'koi8-r',
123 ····'koi8_r':··············'koi8-r',126 ····'koi8_r':··············'koi8-r',
 127 ····'koi8-ru':·············'koi8-u',
124 ····'koi8-u':··············'koi8-u',128 ····'koi8-u':··············'koi8-u',
125 ····'csmacintosh':·········'macintosh',129 ····'csmacintosh':·········'macintosh',
126 ····'mac':·················'macintosh',130 ····'mac':·················'macintosh',
127 ····'macintosh':···········'macintosh',131 ····'macintosh':···········'macintosh',
128 ····'x-mac-roman':·········'macintosh',132 ····'x-mac-roman':·········'macintosh',
129 ····'dos-874':·············'windows-874',133 ····'dos-874':·············'windows-874',
130 ····'iso-8859-11':·········'windows-874',134 ····'iso-8859-11':·········'windows-874',
Offset 190, 26 lines modifiedOffset 194, 26 lines modified
190 ····'gb2312':··············'gbk',194 ····'gb2312':··············'gbk',
191 ····'gb_2312':·············'gbk',195 ····'gb_2312':·············'gbk',
192 ····'gb_2312-80':··········'gbk',196 ····'gb_2312-80':··········'gbk',
193 ····'gbk':·················'gbk',197 ····'gbk':·················'gbk',
194 ····'iso-ir-58':···········'gbk',198 ····'iso-ir-58':···········'gbk',
195 ····'x-gbk':···············'gbk',199 ····'x-gbk':···············'gbk',
196 ····'gb18030':·············'gb18030',200 ····'gb18030':·············'gb18030',
197 ····'hz-gb-2312':··········'hz-gb-2312', 
198 ····'big5':················'big5',201 ····'big5':················'big5',
199 ····'big5-hkscs':··········'big5',202 ····'big5-hkscs':··········'big5',
200 ····'cn-big5':·············'big5',203 ····'cn-big5':·············'big5',
201 ····'csbig5':··············'big5',204 ····'csbig5':··············'big5',
202 ····'x-x-big5':············'big5',205 ····'x-x-big5':············'big5',
203 ····'cseucpkdfmtjapanese':·'euc-jp',206 ····'cseucpkdfmtjapanese':·'euc-jp',
204 ····'euc-jp':··············'euc-jp',207 ····'euc-jp':··············'euc-jp',
205 ····'x-euc-jp':············'euc-jp',208 ····'x-euc-jp':············'euc-jp',
206 ····'csiso2022jp':·········'iso-2022-jp',209 ····'csiso2022jp':·········'iso-2022-jp',
207 ····'iso-2022-jp':·········'iso-2022-jp',210 ····'iso-2022-jp':·········'iso-2022-jp',
208 ····'csshiftjis':··········'shift_jis',211 ····'csshiftjis':··········'shift_jis',
 212 ····'ms932':···············'shift_jis',
209 ····'ms_kanji':············'shift_jis',213 ····'ms_kanji':············'shift_jis',
210 ····'shift-jis':···········'shift_jis',214 ····'shift-jis':···········'shift_jis',
211 ····'shift_jis':···········'shift_jis',215 ····'shift_jis':···········'shift_jis',
212 ····'sjis':················'shift_jis',216 ····'sjis':················'shift_jis',
213 ····'windows-31j':·········'shift_jis',217 ····'windows-31j':·········'shift_jis',
214 ····'x-sjis':··············'shift_jis',218 ····'x-sjis':··············'shift_jis',
215 ····'cseuckr':·············'euc-kr',219 ····'cseuckr':·············'euc-kr',
Offset 218, 14 lines modifiedOffset 222, 24 lines modified
218 ····'iso-ir-149':··········'euc-kr',222 ····'iso-ir-149':··········'euc-kr',
219 ····'korean':··············'euc-kr',223 ····'korean':··············'euc-kr',
220 ····'ks_c_5601-1987':······'euc-kr',224 ····'ks_c_5601-1987':······'euc-kr',
221 ····'ks_c_5601-1989':······'euc-kr',225 ····'ks_c_5601-1989':······'euc-kr',
222 ····'ksc5601':·············'euc-kr',226 ····'ksc5601':·············'euc-kr',
223 ····'ksc_5601':············'euc-kr',227 ····'ksc_5601':············'euc-kr',
224 ····'windows-949':·········'euc-kr',228 ····'windows-949':·········'euc-kr',
225 ····'csiso2022kr':·········'iso-2022-kr',229 ····'csiso2022kr':·········'replacement',
 230 ····'hz-gb-2312':··········'replacement',
 231 ····'iso-2022-cn':·········'replacement',
 232 ····'iso-2022-cn-ext':·····'replacement',
226 ····'iso-2022-kr':·········'iso-2022-kr',233 ····'iso-2022-kr':·········'replacement',
 234 ····'replacement':·········'replacement',
 235 ····'unicodefffe':·········'utf-16be',
227 ····'utf-16be':············'utf-16be',236 ····'utf-16be':············'utf-16be',
 237 ····'csunicode':···········'utf-16le',
 238 ····'iso-10646-ucs-2':·····'utf-16le',
 239 ····'ucs-2':···············'utf-16le',
 240 ····'unicode':·············'utf-16le',
 241 ····'unicodefeff':·········'utf-16le',
228 ····'utf-16':··············'utf-16le',242 ····'utf-16':··············'utf-16le',
229 ····'utf-16le':············'utf-16le',243 ····'utf-16le':············'utf-16le',
230 ····'x-user-defined':······'x-user-defined',244 ····'x-user-defined':······'x-user-defined',
231 }245 }
⊟
44.1 KB
charset_normalizer-3.4.9.dist-info/METADATA vs.
charset_normalizer-3.5.2.dist-info/METADATA
Files 92% similar despite different names
    
Offset 1, 10 lines modifiedOffset 1, 10 lines modified
1 Metadata-Version:·2.41 Metadata-Version:·2.4
2 Name:·charset-normalizer2 Name:·charset-normalizer
3 Version:·3.4.93 Version:·3.5.2
4 Summary:·The·Real·First·Universal·Charset·Detector.·Open,·modern·and·actively·maintained·alternative·to·Chardet.4 Summary:·The·Real·First·Universal·Charset·Detector.·Open,·modern·and·actively·maintained·alternative·to·Chardet.
5 Author-email:·"Ahmed·R.·TAHRI"·<tahri.ahmed@proton.me>5 Author-email:·"Ahmed·R.·TAHRI"·<tahri.ahmed@proton.me>
6 Maintainer-email:·"Ahmed·R.·TAHRI"·<tahri.ahmed@proton.me>6 Maintainer-email:·"Ahmed·R.·TAHRI"·<tahri.ahmed@proton.me>
7 License:·MIT7 License:·MIT
8 Project-URL:·Changelog,·https://github.com/jawah/charset_normalizer/blob/master/CHANGELOG.md8 Project-URL:·Changelog,·https://github.com/jawah/charset_normalizer/blob/master/CHANGELOG.md
9 Project-URL:·Documentation,·https://charset-normalizer.readthedocs.io/9 Project-URL:·Documentation,·https://charset-normalizer.readthedocs.io/
10 Project-URL:·Code,·https://github.com/jawah/charset_normalizer10 Project-URL:·Code,·https://github.com/jawah/charset_normalizer
Offset 19, 18 lines modifiedOffset 19, 21 lines modified
19 Classifier:·Programming·Language·::·Python·::·3.819 Classifier:·Programming·Language·::·Python·::·3.8
20 Classifier:·Programming·Language·::·Python·::·3.920 Classifier:·Programming·Language·::·Python·::·3.9
21 Classifier:·Programming·Language·::·Python·::·3.1021 Classifier:·Programming·Language·::·Python·::·3.10
22 Classifier:·Programming·Language·::·Python·::·3.1122 Classifier:·Programming·Language·::·Python·::·3.11
23 Classifier:·Programming·Language·::·Python·::·3.1223 Classifier:·Programming·Language·::·Python·::·3.12
24 Classifier:·Programming·Language·::·Python·::·3.1324 Classifier:·Programming·Language·::·Python·::·3.13
25 Classifier:·Programming·Language·::·Python·::·3.1425 Classifier:·Programming·Language·::·Python·::·3.14
 26 Classifier:·Programming·Language·::·Python·::·3.15
26 Classifier:·Programming·Language·::·Python·::·3·::·Only27 Classifier:·Programming·Language·::·Python·::·3·::·Only
27 Classifier:·Programming·Language·::·Python·::·Implementation·::·CPython28 Classifier:·Programming·Language·::·Python·::·Implementation·::·CPython
28 Classifier:·Programming·Language·::·Python·::·Implementation·::·PyPy29 Classifier:·Programming·Language·::·Python·::·Implementation·::·PyPy
29 Classifier:·Programming·Language·::·Python·::·Free·Threading·::·4·-·Resilient30 Classifier:·Programming·Language·::·Python·::·Free·Threading·::·4·-·Resilient
 31 Classifier:·Environment·::·WebAssembly
 32 Classifier:·Environment·::·WebAssembly·::·Emscripten
30 Classifier:·Topic·::·Text·Processing·::·Linguistic33 Classifier:·Topic·::·Text·Processing·::·Linguistic
31 Classifier:·Topic·::·Utilities34 Classifier:·Topic·::·Utilities
32 Classifier:·Typing·::·Typed35 Classifier:·Typing·::·Typed
33 Requires-Python:·>=3.736 Requires-Python:·>=3.7
34 Description-Content-Type:·text/markdown37 Description-Content-Type:·text/markdown
35 License-File:·LICENSE38 License-File:·LICENSE
36 Provides-Extra:·unicode-backport39 Provides-Extra:·unicode-backport
Offset 72, 56 lines modifiedOffset 75, 67 lines modified
72 >·You·can·also·register·your·own·set·of·codecs,·and·yes,·it·would·work·as-is.75 >·You·can·also·register·your·own·set·of·codecs,·and·yes,·it·would·work·as-is.
  
73 This·project·offers·you·an·alternative·to·**Universal·Charset·Encoding·Detector**,·also·known·as·**Chardet**.76 This·project·offers·you·an·alternative·to·**Universal·Charset·Encoding·Detector**,·also·known·as·**Chardet**.
  
74 |·Feature··········································|·[Chardet](https://github.com/chardet/chardet)·|·······································Charset·Normalizer········································|·[cChardet](https://github.com/PyYoshi/cChardet)·|77 |·Feature··········································|·[Chardet](https://github.com/chardet/chardet)·|·······································Charset·Normalizer········································|·[cChardet](https://github.com/PyYoshi/cChardet)·|
75 |--------------------------------------------------|:---------------------------------------------:|:-----------------------------------------------------------------------------------------------:|:-----------------------------------------------:|78 |--------------------------------------------------|:---------------------------------------------:|:-----------------------------------------------------------------------------------------------:|:-----------------------------------------------:|
76 |·`Fast`···········································|·······················✅·······················|················································✅················································|························✅························|79 |·`Fast`···········································|·······················✅·······················|················································✅················································|························✅························|
 80 |·`Fast·on·large·content·(uncapped)`···············|·······················❌·······················|················································✅················································|························❌························|
77 |·`Universal`[^1]··································|·······················❌·······················|················································✅················································|························❌························|81 |·`Universal`[^1]··································|·······················❌·······················|················································✅················································|························❌························|
78 |·`Reliable`·**without**·distinguishable·standards·|·······················✅·······················|················································✅················································|························✅························|82 |·`Reliable`·**without**·distinguishable·standards·|·······················✅·······················|················································✅················································|························✅························|
79 |·`Reliable`·**with**·distinguishable·standards····|·······················✅·······················|················································✅················································|························✅························|83 |·`Reliable`·**with**·distinguishable·standards····|·······················✅·······················|················································✅················································|························✅························|
80 |·`License`········································|········_Disputed_[^2]<br>_restrictive_········|···············································MIT···············································|············MPL-1.1<br>_restrictive_·············|84 |·`License`········································|···········_0BSD_[^2]<br>_disputed_············|···············································MIT···············································|············MPL-1.1<br>_restrictive_·············|
81 |·`Native·Python`··································|·······················✅·······················|················································✅················································|························❌························|85 |·`Native·Python`··································|·······················✅·······················|················································✅················································|························❌························|
82 |·`Detect·spoken·language`·························|·······················✅·······················|················································✅················································|·······················N/A·······················|86 |·`Detect·spoken·language`·························|·······················✅·······················|················································✅················································|·······················N/A·······················|
83 |·`UnicodeDecodeError·Safety`······················|·······················✅·······················|················································✅················································|························❌························| 
84 |·`Whl·Size·(min)`·································|····················500·kB·····················|·············································150·kB··············································|·····················~200·kB·····················|87 |·`UnicodeDecodeError·Safety`······················|·······················❌·······················|················································✅················································|························❌························|
 88 |·`Whl·Size`·······································|···················~1200·kB····················|·············································~250·kB·············································|·····················~200·kB·····················|
85 |·`Supported·Encoding`·····························|······················99·······················|·[99](https://charset-normalizer.readthedocs.io/en/latest/user/support.html#supported-encodings)·|·······················40························|89 |·`Supported·Encoding`·····························|······················99·······················|·[99](https://charset-normalizer.readthedocs.io/en/latest/user/support.html#supported-encodings)·|·······················40························|
86 |·`Can·register·custom·encoding`···················|·······················❌·······················|················································✅················································|························❌························|90 |·`Can·register·custom·encoding`···················|·······················❌·······················|················································✅················································|························❌························|
  
87 <p·align="center">91 <p·align="center">
88 <img·src="https://i.imgflip.com/373iay.gif"·alt="Reading·Normalized·Text"·width="226"/><img·src="https://media.tenor.com/images/c0180f70732a18b4965448d33adba3d0/tenor.gif"·alt="Cat·Reading·Text"·width="200"/>92 <img·src="https://i.imgflip.com/373iay.gif"·alt="Reading·Normalized·Text"·width="226"/><img·src="https://media.tenor.com/images/c0180f70732a18b4965448d33adba3d0/tenor.gif"·alt="Cat·Reading·Text"·width="200"/>
89 </p>93 </p>
  
90 [^1]:·They·are·clearly·using·specific·code·for·a·specific·encoding·even·if·covering·most·of·used·one.94 [^1]:·They·are·clearly·using·specific·code·for·a·specific·encoding·even·if·covering·most·of·them.
91 [^2]:·Chardet·7.0+·was·relicensed·from·LGPL-2.1·to·MIT·following·an·AI-assisted·rewrite.·This·relicensing·is·disputed·on·two·independent·grounds:·**(a)**·the·original·author·[contests](https://github.com/chardet/chardet/issues/327)·that·the·maintainer·had·the·right·to·re[·...·truncated·by·diffoscope;·len:·1022,·SHA:·bd8f50206097e27a8557d398b8d7fd66053cb41ebeeabd24186dc25151673471·...·].95 [^2]:·Chardet·7·replaced·the·historical·LGPL-licensed·implementation·with·an·AI-assisted·rewrite,·initially·distributed·under·MIT·and·later·under·0BSD.·The·original·author·[contests](https://github.com/chardet/chardet/issues/327)·that·the·rewrite·was·sufficiently·indepen[·...·truncated·by·diffoscope;·len:·2096,·SHA:·da0513e912930efa168e79bcaaee28017613ad64cc9734c52ca36133c8808e4e·...·].
  
92 ##·⚡·Performance96 ##·⚡·Performance
  
93 This·package·offer·better·performances·against·Chardet.·Here·are·some·numbers.97 This·package·offer·similar·performances·in·general·against·Chardet.·Expect·10X·faster·with·large·contents·when·you·uncap·Chardet·max_bytes·default·assumption.
  
94 |·Package···········································|·Accuracy·|·Mean·per·file·(ms)·|·File·per·sec·(est)·| 
95 |---------------------------------------------------|:--------:|:------------------:|:------------------:| 
96 |·[chardet·7.4](https://github.com/chardet/chardet)·|···89·%···|········3·ms········|····333·file/sec····| 
97 |·charset-normalizer································|·**97·%**·|········1·ms········|···1000·file/sec····|98 |·Package············|·Accuracy·|··Mean·per·file·(ms)···|
 99 |--------------------|:--------:|:---------------------:|
 100 |·Chardet············|···99·%···|·0.4·ms[^4]·0.6·ms[^5]·|
 101 |·charset-normalizer·|···98·%···|········0.4·ms·········|
 102 |·cchardet[^3]·······|···94·%···|········0.6·ms·········|
  
 103 _Well,·sub-ms·detectors·made·them·extremely·discrete·in·the·overall·runtime.
 104 Competitors·can·still·win·individual·measurements,·especially·capped·Chardet·on
 105 small-file·median·latency.·But·when·performance,·accuracy,·binary·handling,·validation
 106 strength,·portability,·and·maintainability·are·considered·together,·charset-normalizer
 107 is·the·stronger·package._
  
 108 |·Package············|···99th·percentile····|·95th·percentile·|·50th·percentile·|
 109 |--------------------|:--------------------:|:---------------:|:---------------:|
 110 |·Chardet············|·2.5·ms[^4]·4.2ms[^5]·|······1·ms·······|·····0.2·ms······|
 111 |·charset-normalizer·|········2.7·ms········|·····1.5·ms······|·····0.2·ms······|
 112 |·cchardet···········|········2.7·ms········|······2·ms·······|·····0.3·ms······|
  
 113 _updated·as·of·August·2026·using·CPython·3.12,·Charset-Normalizer·3.5.1,·and·Chardet·7.5·inside·a·(libc·Debian)·container.·The·host·CPU·is·a·13th·gen·Intel·mobile·CPU.·We'll·no·longer·update·regularly·those·since·the·sub-ms·changes·aren't·meaningful·to·anyone·anymore._
98 |·Package···········································|·99th·percentile·|·95th·percentile·|·50th·percentile·| 
99 |---------------------------------------------------|:---------------:|:---------------:|:---------------:| 
100 |·[chardet·7.4](https://github.com/chardet/chardet)·|······28·ms······|······16·ms······|·····<·1·ms······| 
101 |·charset-normalizer································|······8·ms·······|······5·ms·······|······1·ms·······| 
  
102 _updated·as·of·July·2026·using·CPython·3.12,·Charset-Normalizer·3.4.8,·and·Chardet·7.4.3_ 
  
103 ~Chardet's·performance·on·larger·file·(1MB+)·are·very·poor.·Expect·huge·difference·on·large·payload.~·No·longer·the·case·since·Chardet·7.0+ 
  
104 >·Stats·are·generated·using·400+·files·using·default·parameters.·More·details·on·used·files,·see·GHA·workflows.114 >·Stats·are·generated·using·477·files·using·default·parameters.·More·details·on·used·files,·see·GHA·workflows.
105 >·And·yes,·these·results·might·change·at·any·time.·The·dataset·can·be·updated·to·include·more·files.115 >·And·yes,·these·results·might·change·at·any·time.·The·dataset·can·be·updated·to·include·more·files.
106 >·The·actual·delays·heavily·depends·on·your·CPU·capabilities.·The·factors·should·remain·the·same.116 >·The·actual·delays·heavily·depends·on·your·CPU·capabilities.·The·factors·should·remain·the·same.
107 >·Chardet·claims·on·his·documentation·to·have·a·greater·accuracy·than·us·based·on·the·dataset·they·trained·Chardet·on(...)117 >·Chardet·claims·on·his·documentation·to·have·a·greater·accuracy·than·us·based·on·the·dataset·they·trained·Chardet·on(...)
108 >·Well,·it's·normal,·the·opposite·would·have·been·worrying.·Whereas·charset-normalizer·don't·train·on·anything,·our·solution 
109 >·is·based·on·a·completely·different·algorithm,·still·heuristic·through,·it·does·not·need·weights·across·every·encoding·tables.118 >·Whereas·charset-normalizer·don't·train·on·anything,·our·solution·is·based·on·a·completely·different·algorithm,·still·heuristic
 119 >·through,·it·does·not·need·weights·across·every·encoding·tables.
  
 120 [^3]:·cchardet·main·repository/package·was·discontinued.·we're·relying·on·a·known·fork·namely·faust-cchardet.·the·idea·remained·the·same:·uchardet·bindings.
 121 [^4]:·Chardet·does·not·feed·the·complete·body·but·rather·a·limited·part·of·it,·because·the·algorithm·doesn't·scale·properly·with·larger·samples.·Feeding·the·whole·content·slow·things·to·0.8·ms·(from·the·0.5ms·avg).·While·we·do·not·skip·content·in·order·for·us·to·guarantee·a·usable·result·each·and·every·time.·We·attempted·to·feed·a·272·MiB·UTF-8·(Reddit·archive·on·comments/posts)·file·in·Chardet·uncapped·and·waited·3.4s·while·Charset-Normalizer·took·0.3s,·this·is·a·10-fold·speedup.
 122 [^5]:·Uncapped·max_bytes·(no·truncating·of·content)
  
110 ##·✨·Installation123 ##·✨·Installation
  
111 Using·pip:124 Using·pip:
  
112 ```sh125 ```sh
113 pip·install·charset-normalizer·-U126 pip·install·charset-normalizer·-U
Offset 296, 14 lines modifiedOffset 310, 65 lines modified
  
296 [![OpenSSF·Best·Practices](https://www.bestpractices.dev/projects/7297/badge)](https://www.bestpractices.dev/projects/7297)310 [![OpenSSF·Best·Practices](https://www.bestpractices.dev/projects/7297/badge)](https://www.bestpractices.dev/projects/7297)
  
297 #·Changelog311 #·Changelog
298 All·notable·changes·to·charset-normalizer·will·be·documented·in·this·file.·This·project·adheres·to·[Semantic·Versioning](https://semver.org/spec/v2.0.0.html).312 All·notable·changes·to·charset-normalizer·will·be·documented·in·this·file.·This·project·adheres·to·[Semantic·Versioning](https://semver.org/spec/v2.0.0.html).
299 The·format·is·based·on·[Keep·a·Changelog](https://keepachangelog.com/en/1.0.0/).313 The·format·is·based·on·[Keep·a·Changelog](https://keepachangelog.com/en/1.0.0/).
  
 314 ##·[3.5.2](https://github.com/Ousret/charset_normalizer/compare/3.5.1...3.5.2)·(2026-09-29)
  
 315 ###·Changed
  
 316 -·Raised·the·Cython·upper·bound·to·`<3.4`·for·native·builds.·The·bound·remains·`<3.3`·for
 317 ··`abi3`·builds·to·preserve·compatibility·with·the·Python·3.7·Limited·API.
Max diff block lines reached; 224/17760 bytes (1.26%) of diff not shown.
⊟
26.6 KB
html2text {}
    
Offset 1, 8 lines modifiedOffset 1, 8 lines modified
1 Metadata-Version:·2.4·Name:·charset-normalizer·Version:·3.4.9·Summary:·The·Real1 Metadata-Version:·2.4·Name:·charset-normalizer·Version:·3.5.2·Summary:·The·Real
2 First·Universal·Charset·Detector.·Open,·modern·and·actively·maintained2 First·Universal·Charset·Detector.·Open,·modern·and·actively·maintained
3 alternative·to·Chardet.·Author-email:·"Ahmed·R.·TAHRI"3 alternative·to·Chardet.·Author-email:·"Ahmed·R.·TAHRI"
4 proton.me>·Maintainer-email:·"Ahmed·R.·TAHRI"4 proton.me>·Maintainer-email:·"Ahmed·R.·TAHRI"
5 proton.me>·License:·MIT·Project-URL:·Changelog,·https://github.com/jawah/5 proton.me>·License:·MIT·Project-URL:·Changelog,·https://github.com/jawah/
6 charset_normalizer/blob/master/CHANGELOG.md·Project-URL:·Documentation,·https:/6 charset_normalizer/blob/master/CHANGELOG.md·Project-URL:·Documentation,·https:/
7 /charset-normalizer.readthedocs.io/·Project-URL:·Code,·https://github.com/7 /charset-normalizer.readthedocs.io/·Project-URL:·Code,·https://github.com/
8 jawah/charset_normalizer·Project-URL:·Issue·tracker,·https://github.com/jawah/8 jawah/charset_normalizer·Project-URL:·Issue·tracker,·https://github.com/jawah/
Offset 12, 22 lines modifiedOffset 12, 23 lines modified
12 Classifier:·Operating·System·::·OS·Independent·Classifier:·Programming·Language12 Classifier:·Operating·System·::·OS·Independent·Classifier:·Programming·Language
13 ::·Python·Classifier:·Programming·Language·::·Python·::·3·Classifier:13 ::·Python·Classifier:·Programming·Language·::·Python·::·3·Classifier:
14 Programming·Language·::·Python·::·3.7·Classifier:·Programming·Language·::14 Programming·Language·::·Python·::·3.7·Classifier:·Programming·Language·::
15 Python·::·3.8·Classifier:·Programming·Language·::·Python·::·3.9·Classifier:15 Python·::·3.8·Classifier:·Programming·Language·::·Python·::·3.9·Classifier:
16 Programming·Language·::·Python·::·3.10·Classifier:·Programming·Language·::16 Programming·Language·::·Python·::·3.10·Classifier:·Programming·Language·::
17 Python·::·3.11·Classifier:·Programming·Language·::·Python·::·3.12·Classifier:17 Python·::·3.11·Classifier:·Programming·Language·::·Python·::·3.12·Classifier:
18 Programming·Language·::·Python·::·3.13·Classifier:·Programming·Language·::18 Programming·Language·::·Python·::·3.13·Classifier:·Programming·Language·::
19 Python·::·3.14·Classifier:·Programming·Language·::·Python·::·3·::·Only19 Python·::·3.14·Classifier:·Programming·Language·::·Python·::·3.15·Classifier:
20 Classifier:·Programming·Language·::·Python·::·Implementation·::·CPython 
21 Classifier:·Programming·Language·::·Python·::·Implementation·::·PyPy 
22 Classifier:·Programming·Language·::·Python·::·Free·Threading·::·4·-·Resilient 
23 Classifier:·Topic·::·Text·Processing·::·Linguistic·Classifier:·Topic·:: 
24 Utilities·Classifier:·Typing·::·Typed·Requires-Python:·>=3.7·Description- 
25 Content-Type:·text/markdown·License-File:·LICENSE·Provides-Extra:·unicode- 
26 backport·Dynamic:·license-file20 Programming·Language·::·Python·::·3·::·Only·Classifier:·Programming·Language·::
 21 Python·::·Implementation·::·CPython·Classifier:·Programming·Language·::·Python
 22 ::·Implementation·::·PyPy·Classifier:·Programming·Language·::·Python·::·Free
 23 Threading·::·4·-·Resilient·Classifier:·Environment·::·WebAssembly·Classifier:
 24 Environment·::·WebAssembly·::·Emscripten·Classifier:·Topic·::·Text·Processing
 25 ::·Linguistic·Classifier:·Topic·::·Utilities·Classifier:·Typing·::·Typed
 26 Requires-Python:·>=3.7·Description-Content-Type:·text/markdown·License-File:
 27 LICENSE·Provides-Extra:·unicode-backport·Dynamic:·license-file
27 ··············*\x8**\x8**\x8**\x8**\x8**\x8*·C\x8Ch\x8ha\x8ar\x8rs\x8se\x8et\x8t·D\x8De\x8et\x8te\x8ec\x8ct\x8ti\x8io\x8on\x8n,\x8,·f\x8fo\x8or\x8r·E\x8Ev\x8ve\x8er\x8ry\x8yo\x8on\x8ne\x8e·?\x8ð?\x8Ÿ?\x8‘?\x8‹·*\x8**\x8**\x8**\x8**\x8**\x8*28 ··············*\x8**\x8**\x8**\x8**\x8**\x8*·C\x8Ch\x8ha\x8ar\x8rs\x8se\x8et\x8t·D\x8De\x8et\x8te\x8ec\x8ct\x8ti\x8io\x8on\x8n,\x8,·f\x8fo\x8or\x8r·E\x8Ev\x8ve\x8er\x8ry\x8yo\x8on\x8ne\x8e·?\x8ð?\x8Ÿ?\x8‘?\x8‹·*\x8**\x8**\x8**\x8**\x8**\x8*
28 ···················The·Real·First·Universal·Charset·Detector29 ···················The·Real·First·Universal·Charset·Detector
29 ··_\x8[_\x8h_\x8t_\x8t_\x8p_\x8s_\x8:_\x8/_\x8/_\x8i_\x8m_\x8g_\x8._\x8s_\x8h_\x8i_\x8e_\x8l_\x8d_\x8s_\x8._\x8i_\x8o_\x8/_\x8p_\x8y_\x8p_\x8i_\x8/_\x8p_\x8y_\x8v_\x8e_\x8r_\x8s_\x8i_\x8o_\x8n_\x8s_\x8/_\x8c_\x8h_\x8a_\x8r_\x8s_\x8e_\x8t_\x8__\x8n_\x8o_\x8r_\x8m_\x8a_\x8l_\x8i_\x8z_\x8e_\x8r_\x8._\x8s_\x8v_\x8g_\x8?_\x8o_\x8r_\x8a_\x8n_\x8g_\x8e_\x8=_\x8b_\x8l_\x8u_\x8e_\x8]30 ··_\x8[_\x8h_\x8t_\x8t_\x8p_\x8s_\x8:_\x8/_\x8/_\x8i_\x8m_\x8g_\x8._\x8s_\x8h_\x8i_\x8e_\x8l_\x8d_\x8s_\x8._\x8i_\x8o_\x8/_\x8p_\x8y_\x8p_\x8i_\x8/_\x8p_\x8y_\x8v_\x8e_\x8r_\x8s_\x8i_\x8o_\x8n_\x8s_\x8/_\x8c_\x8h_\x8a_\x8r_\x8s_\x8e_\x8t_\x8__\x8n_\x8o_\x8r_\x8m_\x8a_\x8l_\x8i_\x8z_\x8e_\x8r_\x8._\x8s_\x8v_\x8g_\x8?_\x8o_\x8r_\x8a_\x8n_\x8g_\x8e_\x8=_\x8b_\x8l_\x8u_\x8e_\x8]
30 ·_\x8[_\x8D_\x8o_\x8w_\x8n_\x8l_\x8o_\x8a_\x8d_\x8·_\x8C_\x8o_\x8u_\x8n_\x8t_\x8·_\x8T_\x8o_\x8t_\x8a_\x8l_\x8]_\x8[_\x8h_\x8t_\x8t_\x8p_\x8s_\x8:_\x8/_\x8/_\x8b_\x8e_\x8s_\x8t_\x8p_\x8r_\x8a_\x8c_\x8t_\x8i_\x8c_\x8e_\x8s_\x8._\x8c_\x8o_\x8r_\x8e_\x8i_\x8n_\x8f_\x8r_\x8a_\x8s_\x8t_\x8r_\x8u_\x8c_\x8t_\x8u_\x8r_\x8e_\x8._\x8o_\x8r_\x8g_\x8/_\x8p_\x8r_\x8o_\x8j_\x8e_\x8c_\x8t_\x8s_\x8/31 ·_\x8[_\x8D_\x8o_\x8w_\x8n_\x8l_\x8o_\x8a_\x8d_\x8·_\x8C_\x8o_\x8u_\x8n_\x8t_\x8·_\x8T_\x8o_\x8t_\x8a_\x8l_\x8]_\x8[_\x8h_\x8t_\x8t_\x8p_\x8s_\x8:_\x8/_\x8/_\x8b_\x8e_\x8s_\x8t_\x8p_\x8r_\x8a_\x8c_\x8t_\x8i_\x8c_\x8e_\x8s_\x8._\x8c_\x8o_\x8r_\x8e_\x8i_\x8n_\x8f_\x8r_\x8a_\x8s_\x8t_\x8r_\x8u_\x8c_\x8t_\x8u_\x8r_\x8e_\x8._\x8o_\x8r_\x8g_\x8/_\x8p_\x8r_\x8o_\x8j_\x8e_\x8c_\x8t_\x8s_\x8/
31 ··································_\x87_\x82_\x89_\x87_\x8/_\x8b_\x8a_\x8d_\x8g_\x8e_\x8]32 ··································_\x87_\x82_\x89_\x87_\x8/_\x8b_\x8a_\x8d_\x8g_\x8e_\x8]
32 ·······························Featured·Packages33 ·······························Featured·Packages
33 ·························_\x8[_\x8S_\x8t_\x8a_\x8t_\x8i_\x8c_\x8·_\x8B_\x8a_\x8d_\x8g_\x8e_\x8]_\x8[_\x8S_\x8t_\x8a_\x8t_\x8i_\x8c_\x8·_\x8B_\x8a_\x8d_\x8g_\x8e_\x8]34 ·························_\x8[_\x8S_\x8t_\x8a_\x8t_\x8i_\x8c_\x8·_\x8B_\x8a_\x8d_\x8g_\x8e_\x8]_\x8[_\x8S_\x8t_\x8a_\x8t_\x8i_\x8c_\x8·_\x8B_\x8a_\x8d_\x8g_\x8e_\x8]
Offset 40, 126 lines modifiedOffset 41, 154 lines modified
40 and·yes,·it·would·work·as-is.·This·project·offers·you·an·alternative·to41 and·yes,·it·would·work·as-is.·This·project·offers·you·an·alternative·to
41 **Universal·Charset·Encoding·Detector**,·also·known·as·**Chardet**.·|·Feature·|42 **Universal·Charset·Encoding·Detector**,·also·known·as·**Chardet**.·|·Feature·|
42 [Chardet](https://github.com/chardet/chardet)·|·Charset·Normalizer·|·[cChardet]43 [Chardet](https://github.com/chardet/chardet)·|·Charset·Normalizer·|·[cChardet]
43 (https://github.com/PyYoshi/cChardet)·|·|--------------------------------------44 (https://github.com/PyYoshi/cChardet)·|·|--------------------------------------
44 ------------|:---------------------------------------------:|:-----------------45 ------------|:---------------------------------------------:|:-----------------
45 ------------------------------------------------------------------------------:46 ------------------------------------------------------------------------------:
46 |:-----------------------------------------------:|·|·`Fast`·|·âœ…·|·âœ…·|·âœ…47 |:-----------------------------------------------:|·|·`Fast`·|·âœ…·|·âœ…·|·âœ…
47 |·|·`Universal`[^1]·|·âŒ·|·âœ…·|·âŒ·|·|·`Reliable`·**without** 
48 distinguishable·standards·|·âœ…·|·âœ…·|·âœ…·|·|·`Reliable`·**with** 
49 distinguishable·standards·|·âœ…·|·âœ…·|·âœ…·|·|·`License`·|·_Disputed_[^2] 
50 _restrictive_·|·MIT·|·MPL-1.148 |·|·`Fast·on·large·content·(uncapped)`·|·âŒ·|·âœ…·|·âŒ·|·|·`Universal`[^1]·|
 49 ❌·|·âœ…·|·âŒ·|·|·`Reliable`·**without**·distinguishable·standards·|·âœ…·|
 50 ✅·|·âœ…·|·|·`Reliable`·**with**·distinguishable·standards·|·âœ…·|·âœ…·|·âœ…·|
 51 |·`License`·|·_0BSD_[^2]
 52 _disputed_·|·MIT·|·MPL-1.1
51 _restrictive_·|·|·`Native·Python`·|·âœ…·|·âœ…·|·âŒ·|·|·`Detect·spoken53 _restrictive_·|·|·`Native·Python`·|·âœ…·|·âœ…·|·âŒ·|·|·`Detect·spoken
52 language`·|·âœ…·|·âœ…·|·N/A·|·|·`UnicodeDecodeError·Safety`·|·âœ…·|·âœ…·|·âŒ·|54 language`·|·âœ…·|·âœ…·|·N/A·|·|·`UnicodeDecodeError·Safety`·|·âŒ·|·âœ…·|·âŒ·|
53 |·`Whl·Size·(min)`·|·500·kB·|·150·kB·|·~200·kB·|·|·`Supported·Encoding`·|·99·|55 |·`Whl·Size`·|·~1200·kB·|·~250·kB·|·~200·kB·|·|·`Supported·Encoding`·|·99·|
54 [99](https://charset-normalizer.readthedocs.io/en/latest/user/56 [99](https://charset-normalizer.readthedocs.io/en/latest/user/
55 support.html#supported-encodings)·|·40·|·|·`Can·register·custom·encoding`·|·âŒ57 support.html#supported-encodings)·|·40·|·|·`Can·register·custom·encoding`·|·âŒ
56 |·âœ…·|·âŒ·|58 |·âœ…·|·âŒ·|
57 ··················[Reading·Normalized·Text][Cat·Reading·Text]59 ··················[Reading·Normalized·Text][Cat·Reading·Text]
58 [^1]:·They·are·clearly·using·specific·code·for·a·specific·encoding·even·if60 [^1]:·They·are·clearly·using·specific·code·for·a·specific·encoding·even·if
59 covering·most·of·used·one.·[^2]:·Chardet·7.0+·was·relicensed·from·LGPL-2.1·to 
60 MIT·following·an·AI-assisted·rewrite.·This·relicensing·is·disputed·on·two 
61 independent·grounds:·**(a)**·the·original·author·[contests](https://github.com/ 
62 chardet/chardet/issues/327)·that·the·maintainer·had·the·right·to·relicense, 
63 arguing·the·rewrite·is·a·derivative·work·of·the·LGPL-licensed·codebase·since·it 
64 was·not·a·clean·room·implementation;·**(b)**·the·copyright·claim·itself·is 
65 [questionable](https://github.com/chardet/chardet/issues/334)·given·the·code 
66 was·primarily·generated·by·an·LLM,·and·AI-generated·output·may·not·be 
67 copyrightable·under·most·jurisdictions.·Either·issue·alone·could·undermine·the 
68 MIT·license.·Beyond·licensing,·the·rewrite·raises·questions·about·responsible 
69 use·of·AI·in·open·source:·key·architectural·ideas·pioneered·by·charset- 
70 normalizer·-·notably·decode-first·validity·filtering·(our·foundational·approach 
71 since·v1)·and·encoding·pairwise·similarity·with·the·same·algorithm·and 
72 threshold·â€”·surfaced·in·chardet·7·without·acknowledgment.·The·project·also 
73 imported·test·files·from·charset-normalizer·to·train·and·benchmark·against·it, 
74 then·claimed·superior·accuracy·on·those·very·files.·Charset-normalizer·has 
75 always·been·MIT-licensed,·encoding-agnostic·by·design,·and·built·on·a 
76 verifiable·human-authored·history.·##·âš¡·Performance·This·package·offer·better 
77 performances·against·Chardet.·Here·are·some·numbers.·|·Package·|·Accuracy·| 
78 Mean·per·file·(ms)·|·File·per·sec·(est)·|·|------------------------------------ 
79 ---------------|:--------:|:------------------:|:------------------:|·| 
80 [chardet·7.4](https://github.com/chardet/chardet)·|·89·%·|·3·ms·|·333·file/sec 
81 |·|·charset-normalizer·|·**97·%**·|·1·ms·|·1000·file/sec·|·|·Package·|·99th61 covering·most·of·them.·[^2]:·Chardet·7·replaced·the·historical·LGPL-licensed
 62 implementation·with·an·AI-assisted·rewrite,·initially·distributed·under·MIT·and
 63 later·under·0BSD.·The·original·author·[contests](https://github.com/chardet/
 64 chardet/issues/327)·that·the·rewrite·was·sufficiently·independent·to·permit
 65 relicensing,·while·Chardet's·maintainer·maintains·that·it·is·a·new,·non-
 66 derivative·implementation.·A·separate·[discussion](https://github.com/chardet/
 67 chardet/issues/334)·raises·questions·about·copyright·ownership·and·licensing·of
 68 substantially·AI-generated·code.·Neither·unresolved·question·is·presented·here
 69 as·settled·law.·The·concern·is·broader·than·whether·ideas,·APIs,·or·observable
 70 behavior·are·copyrightable.·Independent·implementations·are·essential·to·open-
 71 source·competition.·The·ethical·question·is·whether·a·maintainer·with·extensive
 72 access·to·a·reciprocal·project's·source,·architecture,·tests,·behavior,
 73 community,·and·reputation·can·use·an·LLM·to·recreate·the·same·product·under·the
 74 same·package·identity,·then·treat·the·generated·implementation·as·a·provenance
 75 reset·that·extinguishes·the·project's·reciprocal·licensing·obligations·and
 76 contributor·expectations.·Responsible·AI·use·in·open·source·requires·more·than
 77 producing·text·that·differs·from·the·historical·source:·it·requires·transparent
 78 provenance,·respect·for·project·lineage,·meaningful·attribution,·accountable
 79 human·review,·and·consideration·for·the·social·agreement·under·which·earlier
 80 contributors·participated.·If·automated·rewriting·becomes·an·accepted·way·to
 81 retain·a·project's·name,·users,·and·accumulated·reputation·while·discarding·its
 82 reciprocal·license,·it·risks·weakening·the·trust·and·incentives·on·which·FOSS
 83 depends.·Early·Chardet·7.x·development·and·evaluation·also·incorporated·files
 84 originating·from·charset-normalizer's·test·corpus.·Results·measured·on·data
 85 that·influenced·implementation·or·model·development·are·not·independent
 86 validation.·Charset-normalizer·has·been·MIT-licensed·since·inception·and
 87 originates·from·a·continuous·human-designed,·encoding-agnostic·project·history.
 88 AI·assistance·may·be·used,·but·every·proposed·change·remains·subject·to
 89 maintainer·review,·adjustment,·testing,·and·accountability;·AI·is·an
 90 engineering·aid,·not·a·mechanism·for·erasing·provenance·or·project·lineage.·An
 91 attentive·eye·will·see·that·some·aspects·lead·by·us·are·magically·found·in
 92 Chardet.·##·âš¡·Performance·This·package·offer·similar·performances·in·general
 93 against·Chardet.·Expect·10X·faster·with·large·contents·when·you·uncap·Chardet
 94 max_bytes·default·assumption.·|·Package·|·Accuracy·|·Mean·per·file·(ms)·|·|----
 95 ----------------|:--------:|:---------------------:|·|·Chardet·|·99·%·|·0.4·ms
 96 [^4]·0.6·ms[^5]·|·|·charset-normalizer·|·98·%·|·0.4·ms·|·|·cchardet[^3]·|·94·%
 97 |·0.6·ms·|·_Well,·sub-ms·detectors·made·them·extremely·discrete·in·the·overall
 98 runtime.·Competitors·can·still·win·individual·measurements,·especially·capped
 99 Chardet·on·small-file·median·latency.·But·when·performance,·accuracy,·binary
 100 handling,·validation·strength,·portability,·and·maintainability·are·considered
 101 together,·charset-normalizer·is·the·stronger·package._·|·Package·|·99th
82 percentile·|·95th·percentile·|·50th·percentile·|·|-----------------------------102 percentile·|·95th·percentile·|·50th·percentile·|·|--------------------|:-------
83 ----------------------|:---------------:|:---------------:|:---------------:|·| 
Max diff block lines reached; 4446/27253 bytes (16.31%) of diff not shown.
⊟
141 B
charset_normalizer-3.4.9.dist-info/licenses/LICENSE vs.
charset_normalizer-3.5.2.dist-info/licenses/LICENSE
Files identical despite different names
⊟
1.2 KB
cssselect2-0.9.0.dist-info/METADATA vs.
cssselect2-0.10.1.dist-info/METADATA
Files 98% similar despite different names
    
Offset 1, 10 lines modifiedOffset 1, 10 lines modified
1 Metadata-Version:·2.41 Metadata-Version:·2.5
2 Name:·cssselect22 Name:·cssselect2
3 Version:·0.9.03 Version:·0.10.1
4 Summary:·CSS·selectors·for·Python·ElementTree4 Summary:·CSS·selectors·for·Python·ElementTree
5 Keywords:·css,elementtree5 Keywords:·css,elementtree
6 Author-email:·Simon·Sapin·<simon.sapin@exyr.org>6 Author-email:·Simon·Sapin·<simon.sapin@exyr.org>
7 Maintainer-email:·CourtBouillon·<contact@courtbouillon.org>7 Maintainer-email:·CourtBouillon·<contact@courtbouillon.org>
8 Requires-Python:·>=3.108 Requires-Python:·>=3.10
9 Description-Content-Type:·text/x-rst9 Description-Content-Type:·text/x-rst
10 Classifier:·Development·Status·::·5·-·Production/Stable10 Classifier:·Development·Status·::·5·-·Production/Stable
Offset 33, 14 lines modifiedOffset 33, 15 lines modified
33 Project-URL:·Code,·https://github.com/Kozea/cssselect2/33 Project-URL:·Code,·https://github.com/Kozea/cssselect2/
34 Project-URL:·Documentation,·https://doc.courtbouillon.org/cssselect2/34 Project-URL:·Documentation,·https://doc.courtbouillon.org/cssselect2/
35 Project-URL:·Donation,·https://opencollective.com/courtbouillon35 Project-URL:·Donation,·https://opencollective.com/courtbouillon
36 Project-URL:·Homepage,·https://doc.courtbouillon.org/cssselect2/36 Project-URL:·Homepage,·https://doc.courtbouillon.org/cssselect2/
37 Project-URL:·Issues,·https://github.com/Kozea/cssselect2/issues37 Project-URL:·Issues,·https://github.com/Kozea/cssselect2/issues
38 Provides-Extra:·doc38 Provides-Extra:·doc
39 Provides-Extra:·test39 Provides-Extra:·test
 40 Import-Name:·cssselect2
  
40 cssselect2·is·a·straightforward·implementation·of·CSS4·Selectors·for·markup41 cssselect2·is·a·straightforward·implementation·of·CSS4·Selectors·for·markup
41 documents·(HTML,·XML,·etc.)·that·can·be·read·by·ElementTree-like·parsers42 documents·(HTML,·XML,·etc.)·that·can·be·read·by·ElementTree-like·parsers
42 (including·cElementTree,·lxml,·html5lib,·etc.)43 (including·cElementTree,·lxml,·html5lib,·etc.)
  
43 *·Free·software:·BSD·license44 *·Free·software:·BSD·license
44 *·For·Python·3.10+,·tested·on·CPython·and·PyPy45 *·For·Python·3.10+,·tested·on·CPython·and·PyPy
⊟
126 B
cssselect2-0.9.0.dist-info/licenses/LICENSE vs.
cssselect2-0.10.1.dist-info/licenses/LICENSE
Files identical despite different names
⊟
1.83 KB
filelock-3.32.0.dist-info/METADATA vs.
filelock-4.1.1.dist-info/METADATA
Files 97% similar despite different names
    
Offset 1, 10 lines modifiedOffset 1, 10 lines modified
1 Metadata-Version:·2.41 Metadata-Version:·2.5
2 Name:·filelock2 Name:·filelock
3 Version:·3.32.03 Version:·4.1.1
4 Summary:·A·platform·independent·file·lock.4 Summary:·A·platform·independent·file·lock.
5 Project-URL:·Documentation,·https://py-filelock.readthedocs.io5 Project-URL:·Documentation,·https://py-filelock.readthedocs.io
6 Project-URL:·Homepage,·https://github.com/tox-dev/py-filelock6 Project-URL:·Homepage,·https://github.com/tox-dev/py-filelock
7 Project-URL:·Source,·https://github.com/tox-dev/py-filelock7 Project-URL:·Source,·https://github.com/tox-dev/py-filelock
8 Project-URL:·Tracker,·https://github.com/tox-dev/py-filelock/issues8 Project-URL:·Tracker,·https://github.com/tox-dev/py-filelock/issues
9 Maintainer-email:·Bernát·Gábor·<gaborjbernat@gmail.com>9 Maintainer-email:·Bernát·Gábor·<gaborjbernat@gmail.com>
10 License-Expression:·MIT10 License-Expression:·MIT
Offset 12, 24 lines modifiedOffset 12, 23 lines modified
12 Keywords:·application,cache,directory,log,user12 Keywords:·application,cache,directory,log,user
13 Classifier:·Development·Status·::·5·-·Production/Stable13 Classifier:·Development·Status·::·5·-·Production/Stable
14 Classifier:·Intended·Audience·::·Developers14 Classifier:·Intended·Audience·::·Developers
15 Classifier:·License·::·OSI·Approved·::·MIT·License15 Classifier:·License·::·OSI·Approved·::·MIT·License
16 Classifier:·Operating·System·::·OS·Independent16 Classifier:·Operating·System·::·OS·Independent
17 Classifier:·Programming·Language·::·Python17 Classifier:·Programming·Language·::·Python
18 Classifier:·Programming·Language·::·Python·::·3·::·Only18 Classifier:·Programming·Language·::·Python·::·3·::·Only
19 Classifier:·Programming·Language·::·Python·::·3.10 
20 Classifier:·Programming·Language·::·Python·::·3.1119 Classifier:·Programming·Language·::·Python·::·3.11
21 Classifier:·Programming·Language·::·Python·::·3.1220 Classifier:·Programming·Language·::·Python·::·3.12
22 Classifier:·Programming·Language·::·Python·::·3.1321 Classifier:·Programming·Language·::·Python·::·3.13
23 Classifier:·Programming·Language·::·Python·::·3.1422 Classifier:·Programming·Language·::·Python·::·3.14
24 Classifier:·Programming·Language·::·Python·::·3.1523 Classifier:·Programming·Language·::·Python·::·3.15
25 Classifier:·Topic·::·Internet24 Classifier:·Topic·::·Internet
26 Classifier:·Topic·::·Software·Development·::·Libraries25 Classifier:·Topic·::·Software·Development·::·Libraries
27 Classifier:·Topic·::·System26 Classifier:·Topic·::·System
28 Requires-Python:·>=3.1027 Requires-Python:·>=3.11
29 Description-Content-Type:·text/markdown28 Description-Content-Type:·text/markdown
  
30 #·filelock29 #·filelock
  
31 [![PyPI](https://img.shields.io/pypi/v/filelock)](https://pypi.org/project/filelock/)30 [![PyPI](https://img.shields.io/pypi/v/filelock)](https://pypi.org/project/filelock/)
32 [![Supported·Python·versions](https://img.shields.io/pypi/pyversions/filelock.svg)](https://pypi.org/project/filelock/)31 [![Supported·Python·versions](https://img.shields.io/pypi/pyversions/filelock.svg)](https://pypi.org/project/filelock/)
33 [![Documentation·status](https://readthedocs.org/projects/py-filelock/badge/?version=latest)](https://py-filelock.readthedocs.io/en/latest/?badge=latest)32 [![Documentation·status](https://readthedocs.org/projects/py-filelock/badge/?version=latest)](https://py-filelock.readthedocs.io/en/latest/?badge=latest)
⊟
122 B
filelock-3.32.0.dist-info/licenses/LICENSE vs.
filelock-4.1.1.dist-info/licenses/LICENSE
Files identical despite different names
⊟
592 B
reportlab-5.0.0.dist-info/METADATA vs.
reportlab-5.0.1.dist-info/METADATA
Files 92% similar despite different names
    
Offset 1, 10 lines modifiedOffset 1, 10 lines modified
1 Metadata-Version:·2.41 Metadata-Version:·2.4
2 Name:·reportlab2 Name:·reportlab
3 Version:·5.0.03 Version:·5.0.1
4 Summary:·The·Reportlab·Toolkit4 Summary:·The·Reportlab·Toolkit
5 Home-page:·https://www.reportlab.com/5 Home-page:·https://www.reportlab.com/
6 Author:·Andy·Robinson,·Robin·Becker,·the·ReportLab·team·and·the·community6 Author:·Andy·Robinson,·Robin·Becker,·the·ReportLab·team·and·the·community
7 Author-email:·reportlab-users@lists2.reportlab.com7 Author-email:·reportlab-users@lists2.reportlab.com
8 License:·BSD·license·(see·license.txt·for·details),·Copyright·(c)·2000-2025,·ReportLab·Inc.8 License:·BSD·license·(see·license.txt·for·details),·Copyright·(c)·2000-2025,·ReportLab·Inc.
9 Classifier:·Development·Status·::·5·-·Production/Stable9 Classifier:·Development·Status·::·5·-·Production/Stable
10 Classifier:·Intended·Audience·::·Developers10 Classifier:·Intended·Audience·::·Developers
⊟
123 B
reportlab-5.0.0.dist-info/licenses/LICENSE vs.
reportlab-5.0.1.dist-info/licenses/LICENSE
Files identical despite different names
⊟
3.69 KB
soupsieve-2.9.1.dist-info/METADATA vs.
soupsieve-3.0.3.dist-info/METADATA
Files 84% similar despite different names
    
Offset 1, 35 lines modifiedOffset 1, 34 lines modified
1 Metadata-Version:·2.41 Metadata-Version:·2.5
2 Name:·soupsieve2 Name:·soupsieve
3 Version:·2.9.13 Version:·3.0.3
4 Summary:·A·modern·CSS·selector·implementation·for·Beautiful·Soup.4 Summary:·A·modern·CSS·selector·implementation·for·Beautiful·Soup.
5 Project-URL:·Homepage,·https://github.com/facelessuser/soupsieve5 Project-URL:·Homepage,·https://github.com/facelessuser/soupsieve
6 Author-email:·Isaac·Muse·<Isaac.Muse@gmail.com>6 Author-email:·Isaac·Muse·<Isaac.Muse@gmail.com>
7 License-Expression:·MIT7 License-Expression:·MIT
8 License-File:·LICENSE.md8 License-File:·LICENSE.md
9 Keywords:·CSS,HTML,XML,filter,query,selector,soup9 Keywords:·CSS,HTML,XML,filter,query,selector,soup
10 Classifier:·Development·Status·::·5·-·Production/Stable10 Classifier:·Development·Status·::·5·-·Production/Stable
11 Classifier:·Environment·::·Console11 Classifier:·Environment·::·Console
12 Classifier:·Intended·Audience·::·Developers12 Classifier:·Intended·Audience·::·Developers
13 Classifier:·License·::·OSI·Approved·::·MIT·License13 Classifier:·License·::·OSI·Approved·::·MIT·License
14 Classifier:·Operating·System·::·OS·Independent14 Classifier:·Operating·System·::·OS·Independent
15 Classifier:·Programming·Language·::·Python·::·315 Classifier:·Programming·Language·::·Python·::·3
16 Classifier:·Programming·Language·::·Python·::·3.10 
17 Classifier:·Programming·Language·::·Python·::·3.1116 Classifier:·Programming·Language·::·Python·::·3.11
18 Classifier:·Programming·Language·::·Python·::·3.1217 Classifier:·Programming·Language·::·Python·::·3.12
19 Classifier:·Programming·Language·::·Python·::·3.1318 Classifier:·Programming·Language·::·Python·::·3.13
20 Classifier:·Programming·Language·::·Python·::·3.1419 Classifier:·Programming·Language·::·Python·::·3.14
 20 Classifier:·Programming·Language·::·Python·::·3.15
21 Classifier:·Topic·::·Internet·::·WWW/HTTP·::·Dynamic·Content21 Classifier:·Topic·::·Internet·::·WWW/HTTP·::·Dynamic·Content
22 Classifier:·Topic·::·Software·Development·::·Libraries·::·Python·Modules22 Classifier:·Topic·::·Software·Development·::·Libraries·::·Python·Modules
23 Classifier:·Typing·::·Typed23 Classifier:·Typing·::·Typed
24 Requires-Python:·>=3.1024 Requires-Python:·>=3.11.5
25 Description-Content-Type:·text/markdown25 Description-Content-Type:·text/markdown
  
26 [![Donate·via·PayPal][donate-image]][donate-link]26 [![Donate·via·PayPal][donate-image]][donate-link]
27 [![Build][github-ci-image]][github-ci-link] 
28 [![Coverage·Status][codecov-image]][codecov-link]27 [![Coverage·Status][codecov-image]][codecov-link]
29 [![PyPI·Version][pypi-image]][pypi-link]28 [![PyPI·Version][pypi-image]][pypi-link]
30 [![PyPI·Downloads][pypi-down]][pypi-link]29 [![PyPI·Downloads][pypi-down]][pypi-link]
31 [![PyPI·-·Python·Version][python-image]][pypi-link]30 [![PyPI·-·Python·Version][python-image]][pypi-link]
32 [![License][license-image-mit]][license-link]31 [![License][license-image-mit]][license-link]
  
33 #·Soup·Sieve32 #·Soup·Sieve
Offset 61, 51 lines modifiedOffset 60, 48 lines modified
61 -·and·[many·more](https://facelessuser.github.io/soupsieve/selectors/)60 -·and·[many·more](https://facelessuser.github.io/soupsieve/selectors/)
  
  
62 ##·Installation61 ##·Installation
  
63 You·must·have·Beautiful·Soup·already·installed:62 You·must·have·Beautiful·Soup·already·installed:
  
64 ```63 ```console
65 pip·install·beautifulsoup464 $·pip·install·beautifulsoup4
66 ```65 ```
  
67 In·most·cases,·assuming·you've·installed·version·4.7.0,·that·should·be·all·you·need·to·do,·but·if·you've·installed·via66 In·most·cases,·assuming·you've·installed·version·4.7.0,·that·should·be·all·you·need·to·do,·but·if·you've·installed·via
68 some·alternative·method,·and·Soup·Sieve·is·not·automatically·installed,·you·can·install·it·directly:67 some·alternative·method,·and·Soup·Sieve·is·not·automatically·installed,·you·can·install·it·directly:
  
69 ```68 ```console
70 pip·install·soupsieve69 $·pip·install·soupsieve
71 ```70 ```
  
72 If·you·want·to·manually·install·it·from·source,·first·ensure·that·[`build`](https://pypi.org/project/build/)·is71 If·you·want·to·manually·install·it·from·source,·first·ensure·that·[`build`](https://pypi.org/project/build/)·is
73 installed:72 installed:
  
74 ```73 ```console
75 pip·install·build74 $·pip·install·build
76 ```75 ```
  
77 Then·navigate·to·the·root·of·the·project·and·build·the·wheel·and·install·(replacing·`<ver>`·with·the·current·version):76 Then·navigate·to·the·root·of·the·project·and·build·the·wheel·and·install·(replacing·`<ver>`·with·the·current·version):
  
78 ```77 ```console
79 python·-m·build·-w78 $·python·-m·build·-w
80 pip·install·dist/soupsieve-<ver>-py3-none-any.whl79 $·pip·install·dist/soupsieve-<ver>-py3-none-any.whl
81 ```80 ```
  
82 ##·Documentation81 ##·Documentation
  
83 Documentation·is·found·here:·https://facelessuser.github.io/soupsieve/.82 Documentation·is·found·here:·https://facelessuser.github.io/soupsieve/.
  
84 ##·License83 ##·License
  
85 MIT84 MIT
  
86 [bs4]:·https://beautiful-soup-4.readthedocs.io/en/latest/#85 [bs4]:·https://beautiful-soup-4.readthedocs.io/en/latest/#
  
87 [github-ci-image]:·https://github.com/facelessuser/soupsieve/workflows/build/badge.svg 
88 [github-ci-link]:·https://github.com/facelessuser/soupsieve/actions?query=workflow%3Abuild+branch%3Amain 
89 [codecov-image]:·https://img.shields.io/codecov/c/github/facelessuser/soupsieve/master.svg?logo=codecov&logoColor=aaaaaa&labelColor=33333386 [codecov-image]:·https://img.shields.io/codecov/c/github/facelessuser/soupsieve/master.svg?logo=codecov&logoColor=aaaaaa&labelColor=333333
90 [codecov-link]:·https://codecov.io/github/facelessuser/soupsieve87 [codecov-link]:·https://codecov.io/github/facelessuser/soupsieve
91 [pypi-image]:·https://img.shields.io/pypi/v/soupsieve.svg?logo=pypi&logoColor=aaaaaa&labelColor=33333388 [pypi-image]:·https://img.shields.io/pypi/v/soupsieve.svg?logo=pypi&logoColor=aaaaaa&labelColor=333333
92 [pypi-down]:·https://img.shields.io/pypi/dm/soupsieve.svg?logo=pypi&logoColor=aaaaaa&labelColor=33333389 [pypi-down]:·https://img.shields.io/pypi/dm/soupsieve.svg?logo=pypi&logoColor=aaaaaa&labelColor=333333
93 [pypi-link]:·https://pypi.python.org/pypi/soupsieve90 [pypi-link]:·https://pypi.python.org/pypi/soupsieve
94 [python-image]:·https://img.shields.io/pypi/pyversions/soupsieve?logo=python&logoColor=aaaaaa&labelColor=33333391 [python-image]:·https://img.shields.io/pypi/pyversions/soupsieve?logo=python&logoColor=aaaaaa&labelColor=333333
95 [license-image-mit]:·https://img.shields.io/badge/license-MIT-blue.svg?labelColor=33333392 [license-image-mit]:·https://img.shields.io/badge/license-MIT-blue.svg?labelColor=333333
⊟
129 B
soupsieve-2.9.1.dist-info/licenses/LICENSE.md vs.
soupsieve-3.0.3.dist-info/licenses/LICENSE.md
Files identical despite different names
⊟
1.83 KB
svglib-2.0.2.dist-info/METADATA vs.
svglib-2.3.0.dist-info/METADATA
Files 98% similar despite different names
    
Offset 1, 10 lines modifiedOffset 1, 10 lines modified
1 Metadata-Version:·2.41 Metadata-Version:·2.5
2 Name:·svglib2 Name:·svglib
3 Version:·2.0.23 Version:·2.3.0
4 Summary:·A·pure-Python·library·for·reading·and·converting·SVG4 Summary:·A·pure-Python·library·for·reading·and·converting·SVG
5 Project-URL:·Homepage,·https://github.com/deeplook/svglib5 Project-URL:·Homepage,·https://github.com/deeplook/svglib
6 Author:·Dinu·Gherman6 Author:·Dinu·Gherman
7 License-Expression:·LGPL-3.0-or-later7 License-Expression:·LGPL-3.0-or-later
8 License-File:·LICENSE.txt8 License-File:·LICENSE.txt
9 Keywords:·PDF,SVG,conversion,graphics,reportlab9 Keywords:·PDF,SVG,conversion,graphics,reportlab
10 Classifier:·Development·Status·::·5·-·Production/Stable10 Classifier:·Development·Status·::·5·-·Production/Stable
Offset 19, 14 lines modifiedOffset 19, 15 lines modified
19 Classifier:·Programming·Language·::·Python19 Classifier:·Programming·Language·::·Python
20 Classifier:·Programming·Language·::·Python·::·3·::·Only20 Classifier:·Programming·Language·::·Python·::·3·::·Only
21 Classifier:·Programming·Language·::·Python·::·3.921 Classifier:·Programming·Language·::·Python·::·3.9
22 Classifier:·Programming·Language·::·Python·::·3.1022 Classifier:·Programming·Language·::·Python·::·3.10
23 Classifier:·Programming·Language·::·Python·::·3.1123 Classifier:·Programming·Language·::·Python·::·3.11
24 Classifier:·Programming·Language·::·Python·::·3.1224 Classifier:·Programming·Language·::·Python·::·3.12
25 Classifier:·Programming·Language·::·Python·::·3.1325 Classifier:·Programming·Language·::·Python·::·3.13
 26 Classifier:·Programming·Language·::·Python·::·3.14
26 Classifier:·Topic·::·Documentation27 Classifier:·Topic·::·Documentation
27 Classifier:·Topic·::·Multimedia·::·Graphics·::·Graphics·Conversion28 Classifier:·Topic·::·Multimedia·::·Graphics·::·Graphics·Conversion
28 Classifier:·Topic·::·Printing29 Classifier:·Topic·::·Printing
29 Classifier:·Topic·::·Software·Development·::·Libraries·::·Python·Modules30 Classifier:·Topic·::·Software·Development·::·Libraries·::·Python·Modules
30 Classifier:·Topic·::·Text·Processing·::·Markup·::·XML31 Classifier:·Topic·::·Text·Processing·::·Markup·::·XML
31 Classifier:·Topic·::·Utilities32 Classifier:·Topic·::·Utilities
32 Requires-Python:·>=3.933 Requires-Python:·>=3.9
Offset 94, 15 lines modifiedOffset 95, 17 lines modified
94 -·support·Python·3.9+·and·PyPy395 -·support·Python·3.9+·and·PyPy3
  
  
95 ##·Known·limitations96 ##·Known·limitations
  
96 -·`@import`·rules·in·stylesheets·are·ignored.·CSS·is·supported,·but·the·range97 -·`@import`·rules·in·stylesheets·are·ignored.·CSS·is·supported,·but·the·range
97 ··of·supported·attributes·is·still·limited98 ··of·supported·attributes·is·still·limited
98 -·clipping·is·limited·to·single·paths,·no·mask·support99 -·clip·paths·support·`path`,·`rect`,·`circle`,·`ellipse`·and·`polygon`·shapes,
 100 ··but·only·one·`clip-rule`·per·`clipPath`.
 101 -·SVG·`mask`·elements·are·not·supported
99 -·SVG·`ForeignObject`·elements·are·not·supported.102 -·SVG·`ForeignObject`·elements·are·not·supported.
  
  
100 ##·Examples103 ##·Examples
  
101 You·can·use·`svglib`·as·a·Python·package·e.g.·like·in·the·following104 You·can·use·`svglib`·as·a·Python·package·e.g.·like·in·the·following
102 interactive·Python·session:105 interactive·Python·session:
⊟
125 B
svglib-2.0.2.dist-info/licenses/LICENSE.txt vs.
svglib-2.3.0.dist-info/licenses/LICENSE.txt
Files identical despite different names
⊟
1.34 KB
assets/chaquopy/build.json
⊟
1.29 KB
Pretty-printed
Similarity: 0.99822695035461% Differences: {"'assets'": "{'requirements-common.imy': 'de1592022f8771860566bfd444c4a59be48264a5'}"}
    
Offset 37, 15 lines modifiedOffset 37, 15 lines modified
37 ········"bootstrap-native/x86_64/math.so":·"b5514fd77493532a51329d69d45b17d386dce4ec",37 ········"bootstrap-native/x86_64/math.so":·"b5514fd77493532a51329d69d45b17d386dce4ec",
38 ········"bootstrap-native/x86_64/mmap.so":·"59d5bdc3daf49510b555e4b5ccfc3182646a8a4d",38 ········"bootstrap-native/x86_64/mmap.so":·"59d5bdc3daf49510b555e4b5ccfc3182646a8a4d",
39 ········"bootstrap-native/x86_64/zlib.so":·"53c15fa2d19cdace60b2828b8e2af1f32e33c5bc",39 ········"bootstrap-native/x86_64/zlib.so":·"53c15fa2d19cdace60b2828b8e2af1f32e33c5bc",
40 ········"bootstrap.imy":·"41a0b4122ce32432b247645932cfb831357a7724",40 ········"bootstrap.imy":·"41a0b4122ce32432b247645932cfb831357a7724",
41 ········"cacert.pem":·"2c68212e96605210eddf740291862bdf59398aef",41 ········"cacert.pem":·"2c68212e96605210eddf740291862bdf59398aef",
42 ········"requirements-arm64-v8a.imy":·"d1c15a21c79bbfb2a21969983a5c3aa363e3572a",42 ········"requirements-arm64-v8a.imy":·"d1c15a21c79bbfb2a21969983a5c3aa363e3572a",
43 ········"requirements-armeabi-v7a.imy":·"d6dc32d2d5d01480de10ad32b4f4b3084ad2e5e6",43 ········"requirements-armeabi-v7a.imy":·"d6dc32d2d5d01480de10ad32b4f4b3084ad2e5e6",
44 ········"requirements-common.imy":·"5b18c0abbf3a27bcc43e8bca3c92d9a91b3c5dcd",44 ········"requirements-common.imy":·"de1592022f8771860566bfd444c4a59be48264a5",
45 ········"requirements-x86_64.imy":·"117873e944235279c1b5cdf8a23cb1ae7bf6cc47",45 ········"requirements-x86_64.imy":·"117873e944235279c1b5cdf8a23cb1ae7bf6cc47",
46 ········"stdlib-arm64-v8a.imy":·"612b92fdeb357374b9d1742707428de8814a2470",46 ········"stdlib-arm64-v8a.imy":·"612b92fdeb357374b9d1742707428de8814a2470",
47 ········"stdlib-armeabi-v7a.imy":·"cd04ebaad8bba14a5bcdc665671090da5631b967",47 ········"stdlib-armeabi-v7a.imy":·"cd04ebaad8bba14a5bcdc665671090da5631b967",
48 ········"stdlib-common.imy":·"e17aea5e7f5d5ef8c9cc260620409eaf7b4bb33b",48 ········"stdlib-common.imy":·"e17aea5e7f5d5ef8c9cc260620409eaf7b4bb33b",
49 ········"stdlib-x86_64.imy":·"43e3c83dba14e01cd82f0167a4152d3c1dbdcc25"49 ········"stdlib-x86_64.imy":·"43e3c83dba14e01cd82f0167a4152d3c1dbdcc25"
50 ····},50 ····},
51 ····"extract_packages":·[51 ····"extract_packages":·[