| Offset 1, 121 lines modified | Offset 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 | ||
| Offset 1, 8 lines modified | Offset 1, 8 lines modified | ||
| 1 | Zip·file·size:·633 | 1 | 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.properties | 2 | -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.textproto | 3 | -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.prof | 4 | -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.profm | 5 | -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.dex | 6 | -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.dex | 7 | -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.so | 8 | -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 modified | Offset 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.so | 70 | -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.so | 71 | -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.imy | 72 | -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.json | 73 | -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.pem | 74 | -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.imy | 75 | -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.imy | 76 | -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··37 | 77 | -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.imy | 78 | -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.imy | 79 | -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.imy | 80 | -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.imy | 81 | -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.imy | 82 | -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.bin | 83 | -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.version | 84 | -rw----·····2.4·fat········6·b-·stor·81-Jan-01·01:01·META-INF/androidx.activity_activity-compose.version |
| Offset 210, 11 lines modified | Offset 210, 8 lines modified | ||
| 210 | -rw----·····0.0·fat······225·b-·stor·81-Jan-01·01:01·res/wN.9.png | 210 | -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.xml | 211 | -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.png | 212 | -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.png | 213 | -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.png | 214 | -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.png | 215 | -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.arsc | 216 | -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 | 21 | 217 | 215·files,·74757732·bytes·uncompressed,·62876922·bytes·compressed:··15.9% |
| Offset 1, 8 lines modified | Offset 1, 8 lines modified | ||
| 1 | Zip·file·size:·37 | 1 | Zip·file·size:·3780927·bytes,·number·of·entries:·772 |
| 2 | -rw----·····2.0·fat····34703·b-·defN·80-Feb-01·00:00·six.py | 2 | -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.py | 3 | -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.py | 5 | -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.py | 6 | -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.py | 7 | -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.py | 8 | -rw----·····2.0·fat·····1753·b-·defN·80-Feb-01·00:00·PIL/BufrStubImagePlugin.py |
| Offset 142, 35 lines modified | Offset 142, 35 lines modified | ||
| 142 | -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·chaquopy_libxml2-2.9.8.dist-info/INSTALLER | 142 | -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/METADATA | 143 | -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/COPYING | 145 | -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/INSTALLER | 146 | -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/METADATA | 147 | -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·····15 | 149 | -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__.py | 150 | -rw----·····2.0·fat······109·b-·defN·80-Feb-01·00:00·charset_normalizer/__main__.py |
| 151 | -rw----·····2.0·fat···· | 151 | -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.py | 152 | -rw----·····2.0·fat····15980·b-·defN·80-Feb-01·00:00·charset_normalizer/cd.py |
| 153 | -rw----·····2.0·fat···· | 153 | -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.py | 154 | -rw----·····2.0·fat·····2651·b-·defN·80-Feb-01·00:00·charset_normalizer/legacy.py |
| 155 | -rw----·····2.0·fat····32 | 155 | -rw----·····2.0·fat····35274·b-·defN·80-Feb-01·00:00·charset_normalizer/md.py |
| 156 | -rw----·····2.0·fat····1 | 156 | -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.typed | 157 | -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·charset_normalizer/py.typed |
| 158 | -rw----·····2.0·fat····1 | 158 | -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.py | 159 | -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__.py | 161 | -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__.py | 162 | -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. | 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. | 164 | -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····4 | 165 | -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. | 166 | -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. | 167 | -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. | 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. | 169 | -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__.py | 171 | -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.py | 172 | -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.py | 173 | -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.py | 174 | -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.py | 175 | -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.py | 176 | -rw----·····2.0·fat·····4059·b-·defN·80-Feb-01·00:00·css_parser/errorhandler.py |
| Offset 226, 23 lines modified | Offset 226, 23 lines modified | ||
| 226 | -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·css_parser-1.1.1.dist-info/INSTALLER | 226 | -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/METADATA | 227 | -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.txt | 228 | -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/COPYING | 230 | -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.LESSER | 231 | -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·····42 | 233 | -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.py | 234 | -rw----·····2.0·fat····18907·b-·defN·80-Feb-01·00:00·cssselect2/compiler.py |
| 235 | -rw----·····2.0·fat····16 | 235 | -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.py | 236 | -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. | 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. | 238 | -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·cssselect2-0.10.1.dist-info/INSTALLER |
| 239 | -rw----·····2.0·fat·····29 | 239 | -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. | 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. | 241 | -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__.py | 243 | -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.py | 244 | -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.py | 245 | -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.py | 246 | -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.py | 247 | -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.py | 248 | -rw----·····2.0·fat····66557·b-·defN·80-Feb-01·00:00·dateutil/rrule.py |
| Offset 276, 42 lines modified | Offset 276, 44 lines modified | ||
| 276 | -rw----·····2.0·fat·····5364·b-·defN·80-Feb-01·00:00·defusedxml/xmlrpc.py | 276 | -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/INSTALLER | 278 | -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/LICENSE | 279 | -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/METADATA | 280 | -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.txt | 281 | -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·····3 | 283 | -rw----·····2.0·fat·····3996·b-·defN·80-Feb-01·00:00·filelock/__init__.py |
| 284 | -rw----·····2.0·fat···· | 284 | -rw----·····2.0·fat····97553·b-·defN·80-Feb-01·00:00·filelock/_api.py |
| 285 | -rw----·····2.0·fat···· | 285 | -rw----·····2.0·fat····14188·b-·defN·80-Feb-01·00:00·filelock/_async.py |
| 286 | -rw----·····2.0·fat····1 | 286 | -rw----·····2.0·fat····14563·b-·defN·80-Feb-01·00:00·filelock/_async_read_write.py |
| 287 | -rw----·····2.0·fat····· | 287 | -rw----·····2.0·fat·····3191·b-·defN·80-Feb-01·00:00·filelock/_descriptor.py |
| 288 | -rw----·····2.0·fat····· | 288 | -rw----·····2.0·fat·····3204·b-·defN·80-Feb-01·00:00·filelock/_error.py |
| 289 | -rw----·····2.0·fat···· | 289 | -rw----·····2.0·fat····14275·b-·defN·80-Feb-01·00:00·filelock/_identity.py |
| 290 | -rw----·····2.0·fat····1 | 290 | -rw----·····2.0·fat····17965·b-·defN·80-Feb-01·00:00·filelock/_lease.py |
| 291 | -rw----·····2.0·fat····· | 291 | -rw----·····2.0·fat·····7164·b-·defN·80-Feb-01·00:00·filelock/_marker.py |
| 292 | -rw----·····2.0·fat···· | 292 | -rw----·····2.0·fat····52720·b-·defN·80-Feb-01·00:00·filelock/_read_write.py |
| 293 | -rw----·····2.0·fat····1 | 293 | -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.py | 294 | -rw----·····2.0·fat······187·b-·defN·80-Feb-01·00:00·filelock/_soft_protocol.py |
| 295 | -rw----·····2.0·fat···· | 295 | -rw----·····2.0·fat····47830·b-·defN·80-Feb-01·00:00·filelock/_strict.py |
| 296 | -rw----·····2.0·fat····· | 296 | -rw----·····2.0·fat·····9220·b-·defN·80-Feb-01·00:00·filelock/_unix.py |
| 297 | -rw----·····2.0·fat····· | 297 | -rw----·····2.0·fat·····7404·b-·defN·80-Feb-01·00:00·filelock/_util.py |
| 298 | -rw----·····2.0·fat····1 | 298 | -rw----·····2.0·fat····17033·b-·defN·80-Feb-01·00:00·filelock/_windows.py |
| 299 | -rw----·····2.0·fat···· | 299 | -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.typed | 300 | -rw----·····2.0·fat········0·b-·defN·80-Feb-01·00:00·filelock/py.typed |
| 301 | -rw----·····2.0·fat······52 | 301 | -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······3 | 303 | -rw----·····2.0·fat······369·b-·defN·80-Feb-01·00:00·filelock/_soft_rw/__init__.py |
| 304 | -rw----·····2.0·fat···· | 304 | -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···· | 307 | -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- | 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- | 309 | -rw----·····2.0·fat········4·b-·defN·80-Feb-01·00:00·filelock-4.1.1.dist-info/INSTALLER |
| 308 | -rw----·····2.0·fat····· | 310 | -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- | 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- | 312 | -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__.py | 314 | -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__.py | 315 | -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.py | 316 | -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.py | 317 | -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.py | 318 | -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.py | 319 | -rw----·····2.0·fat·····4052·b-·defN·80-Feb-01·00:00·html2text/config.py |
| Offset 509, 15 lines modified | Offset 511, 15 lines modified | ||
| 509 | -rw----·····2.0·fat·····3284·b-·defN·80-Feb-01·00:00·reportlab/fonts/hb-test.ttf | 511 | -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______.pfb | 512 | -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______.pfb | 513 | -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______.pfb | 514 | -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______.pfb | 515 | -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__.py | 517 | -rw----·····2.0·fat······274·b-·defN·80-Feb-01·00:00·reportlab/graphics/__init__.py |
| 516 | -rw----·····2.0·fat····15 | 518 | -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.py | 519 | -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.py | 520 | -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.py | 521 | -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.py | 522 | -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.py | 523 | -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. | |||
| Offset 477, 33 lines modified | Offset 477, 33 lines modified | ||
| 477 | Filename:·charset_normalizer/cli/__init__.py | 477 | Filename:·charset_normalizer/cli/__init__.py |
| 478 | Comment:· | 478 | Comment:· |
| 479 | Filename:·charset_normalizer/cli/__main__.py | 479 | Filename:·charset_normalizer/cli/__main__.py |
| 480 | Comment:· | 480 | Comment:· |
| 481 | Filename:·charset_normalizer-3. | 481 | Filename:·charset_normalizer-3.5.2.dist-info/ |
| 482 | Comment:· | 482 | Comment:· |
| 483 | Filename:·charset_normalizer-3. | 483 | Filename:·charset_normalizer-3.5.2.dist-info/INSTALLER |
| 484 | Comment:· | 484 | Comment:· |
| 485 | Filename:·charset_normalizer-3. | 485 | Filename:·charset_normalizer-3.5.2.dist-info/METADATA |
| 486 | Comment:· | 486 | Comment:· |
| 487 | Filename:·charset_normalizer-3. | 487 | Filename:·charset_normalizer-3.5.2.dist-info/entry_points.txt |
| 488 | Comment:· | 488 | Comment:· |
| 489 | Filename:·charset_normalizer-3. | 489 | Filename:·charset_normalizer-3.5.2.dist-info/top_level.txt |
| 490 | Comment:· | 490 | Comment:· |
| 491 | Filename:·charset_normalizer-3. | 491 | Filename:·charset_normalizer-3.5.2.dist-info/licenses/ |
| 492 | Comment:· | 492 | Comment:· |
| 493 | Filename:·charset_normalizer-3. | 493 | 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__.py | 497 | Filename:·css_parser/__init__.py |
| 498 | Comment:· | 498 | Comment:· |
| Offset 699, 27 lines modified | Offset 699, 27 lines modified | ||
| 699 | Filename:·cssselect2/parser.py | 699 | Filename:·cssselect2/parser.py |
| 700 | Comment:· | 700 | Comment:· |
| 701 | Filename:·cssselect2/tree.py | 701 | Filename:·cssselect2/tree.py |
| 702 | Comment:· | 702 | Comment:· |
| 703 | Filename:·cssselect2-0. | 703 | Filename:·cssselect2-0.10.1.dist-info/ |
| 704 | Comment:· | 704 | Comment:· |
| 705 | Filename:·cssselect2-0. | 705 | Filename:·cssselect2-0.10.1.dist-info/INSTALLER |
| 706 | Comment:· | 706 | Comment:· |
| 707 | Filename:·cssselect2-0. | 707 | Filename:·cssselect2-0.10.1.dist-info/METADATA |
| 708 | Comment:· | 708 | Comment:· |
| 709 | Filename:·cssselect2-0. | 709 | Filename:·cssselect2-0.10.1.dist-info/licenses/ |
| 710 | Comment:· | 710 | Comment:· |
| 711 | Filename:·cssselect2-0. | 711 | 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__.py | 715 | Filename:·dateutil/__init__.py |
| 716 | Comment:· | 716 | Comment:· |
| Offset 903, 30 lines modified | Offset 903, 36 lines modified | ||
| 903 | Filename:·filelock/_soft_rw/__init__.py | 903 | Filename:·filelock/_soft_rw/__init__.py |
| 904 | Comment:· | 904 | Comment:· |
| 905 | Filename:·filelock/_soft_rw/_async.py | 905 | 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.py | 911 | Filename:·filelock/_soft_rw/_sync.py |
| 908 | Comment:· | 912 | Comment:· |
| 909 | Filename:·filelock- | 913 | Filename:·filelock-4.1.1.dist-info/ |
| 910 | Comment:· | 914 | Comment:· |
| 911 | Filename:·filelock- | 915 | Filename:·filelock-4.1.1.dist-info/INSTALLER |
| 912 | Comment:· | 916 | Comment:· |
| 913 | Filename:·filelock- | 917 | Filename:·filelock-4.1.1.dist-info/METADATA |
| 914 | Comment:· | 918 | Comment:· |
| 915 | Filename:·filelock- | 919 | Filename:·filelock-4.1.1.dist-info/licenses/ |
| 916 | Comment:· | 920 | Comment:· |
| 917 | Filename:·filelock- | 921 | 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__.py | 925 | Filename:·html2text/__init__.py |
| 922 | Comment:· | 926 | Comment:· |
| Offset 2025, 30 lines modified | Offset 2031, 30 lines modified | ||
| 2025 | Filename:·reportlab/platypus/tables.py | 2031 | Filename:·reportlab/platypus/tables.py |
| 2026 | Comment:· | 2032 | Comment:· |
| 2027 | Filename:·reportlab/platypus/xpreformatted.py | 2033 | Filename:·reportlab/platypus/xpreformatted.py |
| 2028 | Comment:· | 2034 | Comment:· |
| 2029 | Filename:·reportlab-5.0. | 2035 | Filename:·reportlab-5.0.1.dist-info/ |
| 2030 | Comment:· | 2036 | Comment:· |
| 2031 | Filename:·reportlab-5.0. | 2037 | Filename:·reportlab-5.0.1.dist-info/INSTALLER |
| 2032 | Comment:· | 2038 | Comment:· |
| 2033 | Filename:·reportlab-5.0. | 2039 | Filename:·reportlab-5.0.1.dist-info/METADATA |
| 2034 | Comment:· | 2040 | Comment:· |
| 2035 | Filename:·reportlab-5.0. | 2041 | Filename:·reportlab-5.0.1.dist-info/top_level.txt |
| 2036 | Comment:· | 2042 | Comment:· |
| 2037 | Filename:·reportlab-5.0. | 2043 | Filename:·reportlab-5.0.1.dist-info/licenses/ |
| 2038 | Comment:· | 2044 | Comment:· |
| 2039 | Filename:·reportlab-5.0. | 2045 | 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. | |||
| Offset 3532, 35923 lines modified | Offset 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··················· | 3539 | 077477·CRC···················36D9FA28·(920255016) |
| 3540 | 07747B·Compressed·Size·······000003 | 3540 | 07747B·Compressed·Size·······0000031C·(796) |
| 3541 | 07747F·Uncompressed·Size·····000006 | 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·filename | 3547 | #··········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···00000000000006 | 3551 | 0774A9···Uncompressed·Size···000000000000062E·(1582) |
| 3552 | 0774B1···Compressed·Size·····00000000000003 | 3552 | 0774B1···Compressed·Size·····000000000000031C·(796) |
| 3553 | 0774B9·PAYLOAD | 3553 | 0774B9·PAYLOAD | Diff chunk too large, falling back to line-by-line diff (2567 lines added, 2567 lines removed) |
| 3554 | 0777D | 3554 | 0777D5·LOCAL·HEADER·#149·····04034B50·(67324752) |
| 3555 | 0777 | 3555 | 0777D9·Extract·Zip·Spec······14·(20)·'2.0' |
| 3556 | 0777 | 3556 | 0777DA·Extract·OS············00·(0)·'MS-DOS' |
| 3557 | 0777 | 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 | 0777 | 3560 | 0777DD·Compression·Method····0008·(8)·'Deflated' |
| 3561 | 0777 | 3561 | 0777DF·Modification·Time·····00410000·(4259840)·'Fri·Feb··1·00:00:00·1980' |
| 3562 | 0777E | 3562 | 0777E3·CRC···················35633DF4·(895696372) |
| 3563 | 0777E | 3563 | 0777E7·Compressed·Size·······00000055·(85) |
| 3564 | 0777 | 3564 | 0777EB·Uncompressed·Size·····0000006D·(109) |
| 3565 | 0777 | 3565 | 0777EF·Filename·Length·······001E·(30) |
| 3566 | 0777F | 3566 | 0777F1·Extra·Length··········0014·(20) |
| 3567 | 0777F | 3567 | 0777F3·Filename··············'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' |
| 3568 | # | 3568 | # |
| 3569 | #·WARNING:·Offset·0x777F | 3569 | #·WARNING:·Offset·0x777F3:·Filename·'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' |
| 3570 | #··········Zero·length·filename | 3570 | #··········Zero·length·filename |
| 3571 | # | 3571 | # |
| 3572 | 07781 | 3572 | 077811·Extra·ID·#1···········0001·(1)·'ZIP64' |
| 3573 | 07781 | 3573 | 077813···Length··············0010·(16) |
| 3574 | 07781 | 3574 | 077815···Uncompressed·Size···000000000000006D·(109) |
| 3575 | 0778 | 3575 | 07781D···Compressed·Size·····0000000000000055·(85) |
| 3576 | 07782 | 3576 | 077825·PAYLOAD···············XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
| 3577 | 0778 | 3577 | 07787A·LOCAL·HEADER·#150·····04034B50·(67324752) |
| 3578 | 0778 | 3578 | 07787E·Extract·Zip·Spec······14·(20)·'2.0' |
| 3579 | 0778 | 3579 | 07787F·Extract·OS············00·(0)·'MS-DOS' |
| 3580 | 07788 | 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 | 07788 | 3583 | 077882·Compression·Method····0008·(8)·'Deflated' |
| 3584 | 07788 | 3584 | 077884·Modification·Time·····00410000·(4259840)·'Fri·Feb··1·00:00:00·1980' |
| 3585 | 0778 | 3585 | 077888·CRC···················155BD86E·(358340718) |
| 3586 | 0778 | 3586 | 07788C·Compressed·Size·······000020BB·(8379) |
| 3587 | 07789 | 3587 | 077890·Uncompressed·Size·····00008BBE·(35774) |
| 3588 | 07789 | 3588 | 077894·Filename·Length·······0019·(25) |
| 3589 | 07789 | 3589 | 077896·Extra·Length··········0014·(20) |
| 3590 | 0778 | 3590 | 077898·Filename··············'XXXXXXXXXXXXXXXXXXXXXXXXX' |
| 3591 | # | 3591 | # |
| 3592 | #·WARNING:·Offset·0x778 | 3592 | #·WARNING:·Offset·0x77898:·Filename·'XXXXXXXXXXXXXXXXXXXXXXXXX' |
| 3593 | #··········Zero·length·filename | 3593 | #··········Zero·length·filename |
| 3594 | # | 3594 | # |
| 3595 | 0778B | 3595 | 0778B1·Extra·ID·#1···········0001·(1)·'ZIP64' |
| 3596 | 0778B | 3596 | 0778B3···Length··············0010·(16) |
| 3597 | 0778B | 3597 | 0778B5···Uncompressed·Size···0000000000008BBE·(35774) |
| 3598 | 0778 | 3598 | 0778BD···Compressed·Size·····00000000000020BB·(8379) |
| 3599 | 0778C | 3599 | 0778C5·PAYLOAD |
| 3600 | 079 | 3600 | 079980·LOCAL·HEADER·#151·····04034B50·(67324752) |
| 3601 | 079 | 3601 | 079984·Extract·Zip·Spec······14·(20)·'2.0' |
| 3602 | 079 | 3602 | 079985·Extract·OS············00·(0)·'MS-DOS' |
| 3603 | 079 | 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 | 079 | 3606 | 079988·Compression·Method····0008·(8)·'Deflated' |
| 3607 | 079 | 3607 | 07998A·Modification·Time·····00410000·(4259840)·'Fri·Feb··1·00:00:00·1980' |
| 3608 | 079 | 3608 | 07998E·CRC···················16049338·(369398584) |
| 3609 | 079 | 3609 | 079992·Compressed·Size·······000010D3·(4307) |
| 3610 | 079 | 3610 | 079996·Uncompressed·Size·····00003E6C·(15980) |
| 3611 | 079 | 3611 | 07999A·Filename·Length·······0018·(24) |
| 3612 | 079 | 3612 | 07999C·Extra·Length··········0014·(20) |
| 3613 | 079 | 3613 | 07999E·Filename··············'XXXXXXXXXXXXXXXXXXXXXXXX' |
| 3614 | # | 3614 | # |
| 3615 | #·WARNING:·Offset·0x79 | 3615 | #·WARNING:·Offset·0x7999E:·Filename·'XXXXXXXXXXXXXXXXXXXXXXXX' |
| 3616 | #··········Zero·length·filename | 3616 | #··········Zero·length·filename |
| 3617 | # | 3617 | # |
| 3618 | 079 | 3618 | 0799B6·Extra·ID·#1···········0001·(1)·'ZIP64' |
| 3619 | 079 | 3619 | 0799B8···Length··············0010·(16) |
| 3620 | 079 | 3620 | 0799BA···Uncompressed·Size···0000000000003E6C·(15980) |
| 3621 | 079 | 3621 | 0799C2···Compressed·Size·····00000000000010D3·(4307) |
| 3622 | 079 | 3622 | 0799CA·PAYLOAD |
| 3623 | 07A | 3623 | 07AA9D·LOCAL·HEADER·#152·····04034B50·(67324752) |
| 3624 | 07A | 3624 | 07AAA1·Extract·Zip·Spec······14·(20)·'2.0' |
| 3625 | 07A | 3625 | 07AAA2·Extract·OS············00·(0)·'MS-DOS' |
| 3626 | 07A | 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 | 07A | 3629 | 07AAA5·Compression·Method····0008·(8)·'Deflated' |
| 3630 | 07A | 3630 | 07AAA7·Modification·Time·····00410000·(4259840)·'Fri·Feb··1·00:00:00·1980' |
| 3631 | 07A | 3631 | 07AAAB·CRC···················FA97DBAA·(4204256170) |
| 3632 | 07A | 3632 | 07AAAF·Compressed·Size·······00003DB4·(15796) |
| 3633 | 07A | 3633 | 07AAB3·Uncompressed·Size·····0000ED8C·(60812) |
| 3634 | 07A | 3634 | 07AAB7·Filename·Length·······001E·(30) |
| 3635 | 07A | 3635 | 07AAB9·Extra·Length··········0014·(20) |
| 3636 | 07A | 3636 | 07AABB·Filename··············'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' |
| 3637 | # | 3637 | # |
| 3638 | #·WARNING:·Offset·0x7A | 3638 | #·WARNING:·Offset·0x7AABB:·Filename·'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' |
| 3639 | #··········Zero·length·filename | 3639 | #··········Zero·length·filename |
| 3640 | # | 3640 | # |
| 3641 | 07A | 3641 | 07AAD9·Extra·ID·#1···········0001·(1)·'ZIP64' |
| 3642 | 07A | 3642 | 07AADB···Length··············0010·(16) |
| 3643 | 07A | 3643 | 07AADD···Uncompressed·Size···000000000000ED8C·(60812) |
| 3644 | 07A | 3644 | 07AAE5···Compressed·Size·····0000000000003DB4·(15796) |
| 3645 | 07A | 3645 | 07AAED·PAYLOAD |
| 3646 | 07E | 3646 | 07E8A1·LOCAL·HEADER·#153·····04034B50·(67324752) |
| 3647 | 07E | 3647 | 07E8A5·Extract·Zip·Spec······14·(20)·'2.0' |
| 3648 | 07E | 3648 | 07E8A6·Extract·OS············00·(0)·'MS-DOS' |
| 3649 | 07E | 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 | 07E | 3652 | 07E8A9·Compression·Method····0008·(8)·'Deflated' |
| Max diff block lines reached; 2670662/2891635 bytes (92.36%) of diff not shown. | |||
| Offset 11, 15 lines modified | Offset 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·documentation | 15 | 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)· | 17 | :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·annotations | 20 | from·__future__·import·annotations |
| 21 | import·logging | 21 | import·logging |
| Offset 136, 24 lines modified | Offset 136, 22 lines modified | ||
| 136 | ····is_too_small_sequence:·bool·=·len(sequences)·<·TOO_SMALL_SEQUENCE | 136 | ····is_too_small_sequence:·bool·=·len(sequences)·<·TOO_SMALL_SEQUENCE |
| 137 | ····is_too_large_sequence:·bool·=·len(sequences)·>=·TOO_BIG_SEQUENCE | 137 | ····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·( | 141 | ············"Trying·to·detect·encoding·from·a·tiny·portion·of·(%i)·byte(s).", |
| 142 | ············ | 142 | ············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,·( | 147 | ············"Using·lazy·str·decoding·because·the·payload·is·quite·large,·(%i)·byte(s).", |
| 149 | ············ | 148 | ············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·None | 152 | ········any_specified_encoding(sequences)·if·preemptive_behaviour·else·None |
| 155 | ····) | 153 | ····) |
| Offset 166, 20 lines modified | Offset 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·for | 171 | ····#·this·cache·is·mostly·interesting·for |
| 179 | ····#·local·usage.·Garbage·collected·at·the | 172 | ····#·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 modified | Offset 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. | 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 modified | Offset 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 | ············continue | 271 | ············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 modified | Offset 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_up | 467 | ············early_stop_count·=·max_chunk_gave_up |
| 485 | ············lazy_str_hard_failure·=·True | 468 | ············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·content | 470 | ········#·We·might·want·to·check·the·sequence·again·with·the·whole·content, |
| 487 | ········#· | 471 | ········#·but·only·if·initial·MD·tests·passed. |
| 488 | ········if·( | 472 | ········if·( |
| 489 | ············not·lazy_str_hard_failure | 473 | ············not·lazy_str_hard_failure |
| 490 | ············and·is_too_large_sequence | 474 | ············and·is_too_large_sequence |
| 491 | ············and·not·is_multi_byte_decoder | 475 | ············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 | ················continue | 489 | ················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. | |||
| Offset 371, 14 lines modified | Offset 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. | |||
| Offset 1, 37 lines modified | Offset 1, 34 lines modified | ||
| 1 | from·__future__·import·annotations | 1 | from·__future__·import·annotations |
| 2 | import·sys | ||
| 3 | from·functools·import·lru_cache | 2 | from·functools·import·lru_cache |
| 4 | from·logging·import·getLogger | 3 | 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 | ···· | 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 modified | Offset 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·|·_THAI | 40 | _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 modified | Offset 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:·str | 77 | ····character:·str |
| 76 | ····printable:·bool | 78 | ····printable:·bool |
| 77 | ····alpha:·bool | 79 | ····alpha:·bool |
| 78 | ····upper:·bool | 80 | ····upper:·bool |
| 79 | ····lower:·bool | 81 | ····lower:·bool |
| Offset 82, 37 lines modified | Offset 84, 52 lines modified | ||
| 82 | ····digit:·bool | 84 | ····digit:·bool |
| 83 | ····is_ascii:·bool | 85 | ····is_ascii:·bool |
| 84 | ····case_variable:·bool | 86 | ····case_variable:·bool |
| 85 | ····flags:·int | 87 | ····flags:·int |
| 86 | ····accentuated:·bool | 88 | ····accentuated:·bool |
| 87 | ····latin:·bool | 89 | ····latin:·bool |
| 88 | ····is_cjk:·bool | 90 | ····is_cjk:·bool |
| 91 | ····is_katakana:·bool | ||
| 92 | ····is_halfwidth_katakana:·bool | ||
| 89 | ····is_arabic:·bool | 93 | ····is_arabic:·bool |
| 94 | ····is_ligature:·bool | ||
| 95 | ····is_superscript:·bool | ||
| 96 | ····is_sentence_open_punctuation:·bool | ||
| 90 | ····is_glyph:·bool | 97 | ····is_glyph:·bool |
| 91 | ····punct:·bool | 98 | ····punct:·bool |
| 92 | ····sym:·bool | 99 | ····sym:·bool |
| 93 | ····range:·str·|·None | 100 | ····range:·str·|·None |
| 94 | ····sep:·bool | 101 | ····sep:·bool |
| 95 | ····emoticon:·bool | 102 | ····emoticon:·bool |
| 96 | ····safe:·bool | 103 | ····safe:·bool |
| 97 | ····common_cjk:·bool | 104 | ····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·=·character | 109 | ········self.character·=·character |
| 102 | ········#·ASCII·fast-path:·for·characters·with·ord·<·128,·we·can·skip | 110 | ········#·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·=·True | 114 | ············self.is_ascii·=·True |
| 107 | ············self.accentuated·=·False | 115 | ············self.accentuated·=·False |
| 116 | ············self.unaccented·=·character | ||
| Max diff block lines reached; 28287/31487 bytes (89.84%) of diff not shown. | |||
| Offset 36, 15 lines modified | Offset 36, 19 lines modified | ||
| 36 | ········self._string:·str·|·None·=·decoded_payload | 36 | ········self._string:·str·|·None·=·decoded_payload |
| 37 | ········self._preemptive_declaration:·str·|·None·=·preemptive_declaration | 37 | ········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.encoding | 45 | ················return·iana_name(other,·False)·==·self.encoding |
| 42 | ············return·False | 46 | ············return·False |
| 43 | ········return·self.encoding·==·other.encoding·and·self.fingerprint·==·other.fingerprint | 47 | ········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 modified | Offset 68, 19 lines modified | ||
| 64 | ················return·self.chaos·<·other.chaos | 68 | ················return·self.chaos·<·other.chaos |
| 65 | ············return·self.multi_byte_usage·>·other.multi_byte_usage | 69 | ············return·self.multi_byte_usage·>·other.multi_byte_usage |
| 66 | ········return·self.chaos·<·other.chaos | 70 | ········return·self.chaos·<·other.chaos |
| 67 | ····@property | 71 | ····@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))·/· | 77 | ········return·1.0·-·(len(str(self))·/·raw_len) |
| 70 | ····def·__str__(self)·->·str: | 78 | ····def·__str__(self)·->·str: |
| 71 | ········#·Lazy·Str·Loading | 79 | ········#·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·boundary | 82 | ············#·UTF-7·BOM·is·encoded·in·modified·Base64·whose·byte·boundary |
| 75 | ············#·can·overlap·with·the·next·character,·so·raw-byte·stripping | 83 | ············#·can·overlap·with·the·next·character,·so·raw-byte·stripping |
| Offset 254, 24 lines modified | Offset 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._results | 275 | ········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·result | 288 | ····················return·result |
| 274 | ········raise·KeyError | 289 | ········raise·KeyError |
| Offset 296, 22 lines modified | Offset 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 | ····················return | 317 | ····················return |
| 302 | ········self._results.append(item) | 318 | ········self._results.append(item) |
| 303 | ········self._ | 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·None | 325 | ············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() |
| Offset 1, 37 lines modified | Offset 1, 42 lines modified | ||
| 1 | from·__future__·import·annotations | 1 | from·__future__·import·annotations |
| 2 | import·importlib | 2 | import·importlib |
| 3 | import·logging | 3 | import·logging |
| 4 | import·unicodedata | 4 | import·unicodedata |
| 5 | from·bisect·import·bisect_right | 5 | from·bisect·import·bisect_right |
| 6 | from·codecs·import·IncrementalDecoder | 6 | from·codecs·import·IncrementalDecoder |
| 7 | from·encodings.aliases·import·aliases | ||
| 8 | from·functools·import·lru_cache | 7 | from·functools·import·lru_cache |
| 9 | from·re·import·findall | ||
| 10 | from·typing·import·Generator | 8 | 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 modified | Offset 49, 43 lines modified | ||
| 44 | ········flags·|=·_LATIN | 49 | ········flags·|=·_LATIN |
| 45 | ····if·"CJK"·in·desc: | 50 | ····if·"CJK"·in·desc: |
| 46 | ········flags·|=·_CJK | 51 | ········flags·|=·_CJK |
| 47 | ····if·"HANGUL"·in·desc: | 52 | ····if·"HANGUL"·in·desc: |
| 48 | ········flags·|=·_HANGUL | 53 | ········flags·|=·_HANGUL |
| 49 | ····if·"KATAKANA"·in·desc: | 54 | ····if·"KATAKANA"·in·desc: |
| 50 | ········flags·|=·_KATAKANA | 55 | ········flags·|=·_KATAKANA |
| 56 | ········if·"HALFWIDTH"·in·desc: | ||
| 57 | ············flags·|=·_HALFWIDTH_KATAKANA | ||
| 51 | ····if·"HIRAGANA"·in·desc: | 58 | ····if·"HIRAGANA"·in·desc: |
| 52 | ········flags·|=·_HIRAGANA | 59 | ········flags·|=·_HIRAGANA |
| 53 | ····if·"THAI"·in·desc: | 60 | ····if·"THAI"·in·desc: |
| 54 | ········flags·|=·_THAI | 61 | ········flags·|=·_THAI |
| 55 | ····if·"ARABIC"·in·desc: | 62 | ····if·"ARABIC"·in·desc: |
| 56 | ········flags·|=·_ARABIC | 63 | ········flags·|=·_ARABIC |
| 57 | ········if·"ISOLATED·FORM"·in·desc: | 64 | ········if·"ISOLATED·FORM"·in·desc: |
| 58 | ············flags·|=·_ARABIC_ISOLATED_FORM | 65 | ············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·|=·_ACCENTUATED | 74 | ············flags·|=·_ACCENTUATED |
| 62 | ············break | 75 | ············break |
| 63 | ····return·flags | 76 | ····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·character | 82 | ········return·character |
| 71 | ····codes:·list[str]·=·decomposed.split("·") | 83 | ····codes:·list[str]·=·decomposed.split("·") |
| Offset 91, 14 lines modified | Offset 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_ord | 112 | ····#·Binary·search:·find·the·rightmost·range·whose·start·<=·character_ord |
| 97 | ····idx·=·bisect_right(_UNICODE_RANGE_STARTS,·character_ord)·-·1 | 113 | ····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·name | 117 | ············return·name |
| Offset 151, 64 lines modified | Offset 168, 54 lines modified | ||
| 151 | ········return·True | 168 | ········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. | |||
| Offset 1, 8 lines modified | Offset 1, 8 lines modified | ||
| 1 | """ | 1 | """ |
| 2 | Expose·version | 2 | Expose·version |
| 3 | """ | 3 | """ |
| 4 | from·__future__·import·annotations | 4 | from·__future__·import·annotations |
| 5 | __version__·=·"3. | 5 | __version__·=·"3.5.2" |
| 6 | VERSION·=·__version__.split(".") | 6 | VERSION·=·__version__.split(".") |
| Offset 9, 15 lines modified | Offset 9, 15 lines modified | ||
| 9 | from·webencodings·import·ascii_lower | 9 | from·webencodings·import·ascii_lower |
| 10 | #·Classes·are·imported·here·to·expose·them·at·the·top·level·of·the·module | 10 | #·Classes·are·imported·here·to·expose·them·at·the·top·level·of·the·module |
| 11 | from·.compiler·import·compile_selector_list··#·noqa | 11 | from·.compiler·import·compile_selector_list··#·noqa |
| 12 | from·.parser·import·SelectorError··#·noqa | 12 | from·.parser·import·SelectorError··#·noqa |
| 13 | from·.tree·import·ElementWrapper··#·noqa | 13 | from·.tree·import·ElementWrapper··#·noqa |
| 14 | VERSION·=·__version__·=·'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·=·{} |
| Offset 5, 14 lines modified | Offset 5, 16 lines modified | ||
| 5 | SUPPORTED_PSEUDO_ELEMENTS·=·{ | 5 | SUPPORTED_PSEUDO_ELEMENTS·=·{ |
| 6 | ····#·As·per·CSS·Pseudo-Elements·Module·Level·4 | 6 | ····#·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·Module | 10 | ····#·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·1 | 14 | ····#·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``. |
| Offset 1, 26 lines modified | Offset 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·annotations | 8 | from·__future__·import·annotations |
| 7 | import·sys | 9 | import·sys |
| 8 | import·warnings | 10 | import·warnings |
| 9 | from·typing·import·TYPE_CHECKING,·Final | 11 | from·typing·import·TYPE_CHECKING,·Final |
| 10 | from·._api·import·AcquireReturnProxy,·BaseFileLock,·CloseErrorPolicy,·ContextErrorPolicy,·LockOptions | 12 | from·._api·import·AcquireReturnProxy,·BaseFileLock,·CloseErrorPolicy,·ContextErrorPolicy,·LockOptions |
| 11 | from·._descriptor·import·lock_descriptor,·unlock_descriptor | 13 | from·._descriptor·import·lock_descriptor,·unlock_descriptor |
| 12 | from·._error·import·LeaseSettingsMismatch,·SoftFileLockLifetimeWarning,·SoftFileLockProtocolError,·Timeout | 14 | from·._error·import·LeaseSettingsMismatch,·SoftFileLockLifetimeWarning,·SoftFileLockProtocolError,·Timeout |
| 13 | from·._lease·import·LeaseCompromise,·SoftFileLease | 15 | from·._lease·import·CompromiseReason,·LeaseCompromise,·SoftFileLease |
| 14 | from·._marker·import·MarkerSoftFileLock,·OwnerRecord | 16 | 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·ReadWriteLock | 22 | ····from·._read_write·import·ReadWriteLock |
| Offset 32, 30 lines modified | Offset 36, 39 lines modified | ||
| 32 | ········AsyncAcquireReadWriteReturnProxy·=·None | 36 | ········AsyncAcquireReadWriteReturnProxy·=·None |
| 33 | ········AsyncReadWriteLock·=·None | 37 | ········AsyncReadWriteLock·=·None |
| 34 | ········ReadWriteLock·=·None | 38 | ········ReadWriteLock·=·None |
| 35 | from·._soft·import·SoftFileLock | 39 | from·._soft·import·SoftFileLock |
| 36 | from·._soft_rw·import·AsyncAcquireSoftReadWriteReturnProxy,·AsyncSoftReadWriteLock,·SoftReadWriteLock | 40 | from·._soft_rw·import·AsyncAcquireSoftReadWriteReturnProxy,·AsyncSoftReadWriteLock,·SoftReadWriteLock |
| 37 | from·._strict·import·StrictSoftFileClaim,·StrictSoftFileClaimState,·StrictSoftFileLock | 41 | from·._strict·import·StrictSoftFileClaim,·StrictSoftFileClaimState,·StrictSoftFileLock |
| 38 | from·._unix·import·UnixFileLock | 42 | from·._unix·import·UnixFileLock |
| 43 | from·._unix·import·has_fcntl·as·_has_fcntl | ||
| 39 | from·._windows·import·WindowsFileLock | 44 | 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·version | 55 | from·.version·import·version |
| 50 | #:·version·of·the·project·as·a·string | 56 | #:·version·of·the·project·as·a·string |
| 51 | __version__:·Final[str]·=·version | 57 | __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·cover | 63 | if·sys.platform·==·"win32":··#·pragma:·win32·cover |
| 53 | ····_FileLock:·type[BaseFileLock]·=·WindowsFileLock | 64 | ····_FileLock:·type[BaseFileLock]·=·WindowsFileLock |
| 54 | ····_AsyncFileLock:·type[BaseAsyncFileLock]·=·AsyncWindowsFileLock | 65 | ····_AsyncFileLock:·type[BaseAsyncFileLock]·=·AsyncWindowsFileLock |
| 55 | else:··#·pragma:·win32·no·cover·#·ruff:ignore[collapsible-else-if]··#·the·else·carries·the·win32·no-cover·pragma | 66 | 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]·=·UnixFileLock | 68 | ········_FileLock:·type[BaseFileLock]·=·UnixFileLock |
| Offset 86, 30 lines modified | Offset 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 | ] |
| Offset 2, 49 lines modified | Offset 2, 57 lines modified | ||
| 2 | import·contextlib | 2 | import·contextlib |
| 3 | import·inspect | 3 | import·inspect |
| 4 | import·logging | 4 | import·logging |
| 5 | import·math | 5 | import·math |
| 6 | import·os | 6 | import·os |
| 7 | import·secrets | 7 | import·secrets |
| 8 | import·stat | ||
| 8 | import·sys | 9 | import·sys |
| 9 | import·time | 10 | import·time |
| 10 | import·warnings | 11 | import·warnings |
| 11 | from·abc·import·ABCMeta,·abstractmethod | 12 | from·abc·import·ABCMeta,·abstractmethod |
| 12 | from·collections.abc·import·Callable,·Hashable | 13 | from·collections.abc·import·Callable,·Hashable |
| 13 | from·contextlib·import·contextmanager | 14 | from·contextlib·import·contextmanager |
| 14 | from·dataclasses·import·dataclass | 15 | from·dataclasses·import·dataclass,·fields |
| 16 | from·decimal·import·Decimal | ||
| 15 | from·itertools·import·count,·starmap | 17 | from·itertools·import·count,·starmap |
| 18 | from·numbers·import·Real | ||
| 16 | from·threading·import·Condition,·RLock,·get_ident,·local | 19 | from·threading·import·TIMEOUT_MAX,·Condition,·RLock,·Thread,·current_thread,·get_ident,·local |
| 17 | from·typing·import·TYPE_CHECKING,·Final,·Literal,·NoReturn,·TypedDict,·TypeVar,·cast | 20 | from·typing·import·TYPE_CHECKING,·Final,·Generic,·Literal,·NoReturn,·TypedDict,·TypeVar,·cast |
| 18 | from·weakref·import·WeakKeyDictionary,·WeakValueDictionary | 21 | from·weakref·import·WeakKeyDictionary,·WeakValueDictionary |
| 19 | from·._error·import·SoftFileLockLifetimeWarning,·Timeout | 22 | from·._error·import·SoftFileLockLifetimeWarning,·Timeout |
| 20 | from·._util·import·break_lock_file | 23 | 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·pick | 24 | #:·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]·=·-1 | 26 | _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]·=·20 | 29 | _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·Generator | 37 | ····from·collections.abc·import·Generator,·Mapping |
| 34 | ····from·types·import·TracebackType | 38 | ····from·types·import·FrameType,·TracebackType |
| 35 | ····from·typing·import·Protocol | 39 | ····from·typing·import·Protocol |
| 40 | ····from·_typeshed·import·Unused | ||
| 41 | ····from·._lease·import·_LeaseClaim | ||
| 36 | ····from·._read_write·import·ReadWriteLock | 42 | ····from·._read_write·import·ReadWriteLock |
| 37 | ····from·._soft_rw·import·SoftReadWriteLock | 43 | ····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 modified | Offset 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 | ···· | 74 | ····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·None | 77 | _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 modified | Offset 97, 28 lines modified | ||
| 92 | ····context_error_policy:·ContextErrorPolicy | 97 | ····context_error_policy:·ContextErrorPolicy |
| 93 | ····close_error_policy:·CloseErrorPolicy | 98 | ····close_error_policy:·CloseErrorPolicy |
| 94 | ····fallback_to_soft:·bool | 99 | ····fallback_to_soft:·bool |
| 95 | ····preserve_lock_file:·bool | 100 | ····preserve_lock_file:·bool |
| 96 | ····on_acquired:·Callable[[int],·None]·|·None | 101 | ····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·=· | 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·None | 116 | ····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 modified | Offset 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__·=·None | 136 | ············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· | 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. | |||
| Offset 4, 18 lines modified | Offset 4, 26 lines modified | ||
| 4 | import·asyncio | 4 | import·asyncio |
| 5 | import·contextlib | 5 | import·contextlib |
| 6 | import·time | 6 | import·time |
| 7 | from·concurrent.futures·import·Future·as·ConcurrentFuture | 7 | from·concurrent.futures·import·Future·as·ConcurrentFuture |
| 8 | from·dataclasses·import·dataclass | 8 | from·dataclasses·import·dataclass |
| 9 | from·threading·import·Lock | 9 | from·threading·import·Lock |
| 10 | from·typing·import·TYPE_CHECKING,·Final,·Generic,·TypeVar,·cast | 10 | 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·Async | 15 | ····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 | ····pass | 21 | ····pass |
| Offset 28, 23 lines modified | Offset 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·=·None | 39 | ········self._tail:·ConcurrentFuture[None]·|·None·=·None |
| 32 | ····@contextlib.asynccontextmanager | 40 | ····@contextlib.asynccontextmanager |
| 33 | ····async·def·hold(self)·->·Async | 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._tail | 44 | ············predecessor·=·self._tail |
| 37 | ············self._tail·=·ticket | 45 | ············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·as | 49 | ············except·BaseException: |
| 42 | ················predecessor.add_done_callback(lambda·_predecessor:·self._leave(ticket)) | 50 | ················predecessor.add_done_callback(lambda·_predecessor:·self._leave(ticket)) |
| 43 | ················raise | 51 | ················raise |
| 44 | ········try: | 52 | ········try: |
| 45 | ············yield | 53 | ············yield |
| 46 | ········finally: | 54 | ········finally: |
| 47 | ············self._leave(ticket) | 55 | ············self._leave(ticket) |
| Offset 52, 15 lines modified | Offset 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 | ····)·->·Async | 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._tail | 70 | ············predecessor·=·self._tail |
| 63 | ············self._tail·=·ticket | 71 | ············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 modified | Offset 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·=·None | 115 | ················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. | |||
| Offset 2, 50 lines modified | Offset 2, 58 lines modified | ||
| 2 | from·__future__·import·annotations | 2 | from·__future__·import·annotations |
| 3 | import·asyncio | 3 | import·asyncio |
| 4 | import·functools | 4 | import·functools |
| 5 | import·os | 5 | import·os |
| 6 | import·sqlite3 | 6 | import·sqlite3 |
| 7 | import·threading | ||
| 7 | from·concurrent.futures·import·ThreadPoolExecutor | 8 | from·concurrent.futures·import·ThreadPoolExecutor |
| 8 | from·contextlib·import·asynccontextmanager | 9 | from·contextlib·import·asynccontextmanager |
| 9 | from·typing·import·TYPE_CHECKING,·ParamSpec,·TypeVar | 10 | 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· | 17 | 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·ReadWriteLock | 26 | from·._read_write·import·ReadWriteLock |
| 19 | if·TYPE_CHECKING: | 27 | if·TYPE_CHECKING: |
| 20 | ····from·collections.abc·import·AsyncGenerator,·Callable | 28 | ····from·collections.abc·import·AsyncGenerator,·Callable |
| 21 | ····from·concurrent·import·futures | 29 | ····from·concurrent·import·futures |
| 22 | ····from·types·import·TracebackType | 30 | ····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()``·because | 36 | ····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 | ···· | 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·lock | 41 | ····:param·lock_file:·path·to·the·SQLite·database·file·used·as·the·lock |
| 34 | ····:param·timeout:·maximum·wait·time·in·seconds;·``-1``· | 42 | ····: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·unavailable | 43 | ····: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·path | 44 | ····: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·loop | 45 | ····: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·dedicated | 46 | ····: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·it | 47 | ········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·passing | 48 | ········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 modified | Offset 75, 15 lines modified | ||
| 67 | ········creator_pid·=·os.getpid() | 75 | ········creator_pid·=·os.getpid() |
| 68 | ········self._creator_pid·=·creator_pid | 76 | ········self._creator_pid·=·creator_pid |
| 69 | ········self._fork_invalidated·=·False | 77 | ········self._fork_invalidated·=·False |
| 70 | ········self._closed·=·False | 78 | ········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·=·loop | 83 | ············self._loop·=·loop |
| 75 | ············self._owns_executor·=·executor·is·None | 84 | ············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·child | 86 | ············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 modified | Offset 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·default | 120 | ········: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·default | 121 | ········: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·=·None | 124 | ········body_error:·BaseException·|·None·=·None |
| 120 | ········try: | 125 | ········try: |
| 121 | ············yield | 126 | ············yield |
| 122 | ········except·BaseException·as·error: | 127 | ········except·BaseException·as·error: |
| 123 | ············body_error·=·error | 128 | ············body_error·=·error |
| 124 | ············raise | 129 | ············raise |
| Offset 135, 18 lines modified | Offset 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·default | 141 | ········: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·default | 142 | ········: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·=·None | 145 | ········body_error:·BaseException·|·None·=·None |
| 145 | ········try: | 146 | ········try: |
| 146 | ············yield | 147 | ············yield |
| 147 | ········except·BaseException·as·error: | 148 | ········except·BaseException·as·error: |
| 148 | ············body_error·=·error | 149 | ············body_error·=·error |
| 149 | ············raise | 150 | ············raise |
| Offset 157, 67 lines modified | Offset 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 | ············raise | 163 | ············raise |
| 163 | ····async·def·acquire_read( | 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. | |||
| Offset 1, 16 lines modified | Offset 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·annotations | 2 | from·__future__·import·annotations |
| 3 | import·sys | 3 | import·sys |
| 4 | import·time | 4 | import·time |
| 5 | from· | 5 | from·threading·import·TIMEOUT_MAX |
| 6 | from·typing·import·Final | 6 | from·typing·import·Final |
| 7 | from·._api·import·_seconds | ||
| 7 | if·sys.platform·==·"win32":··#·pragma:·win32·cover | 8 | if·sys.platform·==·"win32":··#·pragma:·win32·cover |
| 8 | ····from·._windows·import·_lock_fd_nonblocking,·_unlock_fd | 9 | ····from·._windows·import·_lock_fd_nonblocking,·_unlock_fd |
| 9 | else:··#·pragma:·win32·no·cover | 10 | else:··#·pragma:·win32·no·cover |
| 10 | ····from·._unix·import·_lock_fd_nonblocking,·_unlock_fd | 11 | ····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 modified | Offset 26, 31 lines modified | ||
| 24 | ····For·timeout,·reentrancy,·singleton,·lifetime,·or·stale-break·behavior,·use·:class:`FileLock`.·There·is·no·async | 26 | ····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·it | 29 | ····: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 | ········ | 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·the | 34 | ····: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· | 36 | ····:raises·ValueError:·if·a·blocking·call·receives·a·*poll_interval*·outside·that·range,·including·``nan``. |
| 35 | ····..·versionadded::·3.30.0 | 37 | ····..·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 | ····i | 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· | 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·True | 47 | ····return·True |
| 45 | def·unlock_descriptor(fd:·int)·->·None: | 48 | def·unlock_descriptor(fd:·int)·->·None: |
| Offset 1, 35 lines modified | Offset 1, 47 lines modified | ||
| 1 | from·__future__·import·annotations | 1 | 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·API | 3 | 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_file | 7 | ········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 | ········#· | 10 | ········#·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-link | 12 | ····def·__str__(self)·->·str:··#·pragma:·needs·hard-link |
| 11 | ········ | 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 | ····@property | 19 | ····@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_file | 22 | ········return·self._lock_file |
| 18 | class·SoftFileLockLifetimeWarning( | 23 | class·SoftFileLockLifetimeWarning(FutureWarning): |
| 24 | ····""" | ||
| 19 | ···· | 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·API | 29 | 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 modified | Offset 51, 18 lines modified | ||
| 39 | ········self._lock_file·=·lock_file | 51 | ········self._lock_file·=·lock_file |
| 40 | ········self._claim_name·=·claim_name | 52 | ········self._claim_name·=·claim_name |
| 41 | ········self._reason·=·reason | 53 | ········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[ | 57 | ····)·->·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 | ····@property | 64 | ····@property |
| 51 | ····def·lock_file(self)·->·str:··#·pragma:·needs·hard-link | 65 | ····def·lock_file(self)·->·str:··#·pragma:·needs·hard-link |
| Offset 1, 40 lines modified | Offset 1, 99 lines modified | ||
| 1 | from·__future__·import·annotations | 1 | from·__future__·import·annotations |
| 2 | import·hashlib | ||
| 2 | import·os | 3 | import·os |
| 3 | import·socket | 4 | import·socket |
| 4 | import·sys | 5 | import·sys |
| 5 | from·errno·import·EPERM,·ESRCH | 6 | from·errno·import·EPERM,·ESRCH |
| 6 | from·pathlib·import·Path | 7 | from·pathlib·import·Path |
| 7 | from·typing·import·Final | 8 | 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 | ···· | 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·from | 56 | ····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·the | 57 | ····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·that | 58 | ····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·death | 59 | ····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·False | 63 | ········return·False |
| 22 | ····if·no | 64 | ····if·process_alive(pid)·and·(start_token·is·None·or·process_start_token(pid)·in·{None,·start_token}): |
| 23 | ········return· | 65 | ········return·False |
| 24 | ····if· | 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·False | 76 | ········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·cover | 78 | if·sys.platform·==·"win32":··#·pragma:·win32·cover |
| 29 | ····import·ctypes | 79 | ····import·ctypes |
| 30 | ····from·ctypes·import·wintypes | 80 | ····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 modified | Offset 189, 47 lines modified | ||
| 130 | ················return·None | 189 | ················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·integer | 192 | ············except·ValueError:··#·pragma:·no·cover··#·/proc·always·renders·starttime·as·an·integer |
| 134 | ················return·None | 193 | ················return·None |
| 135 | ············return·(_BOOT_ID·<<·64)·|·starttime | 194 | ············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. | |||
| Offset 1, 37 lines modified | Offset 1, 39 lines modified | ||
| 1 | from·__future__·import·annotations | 1 | from·__future__·import·annotations |
| 2 | import·os | 2 | import·os |
| 3 | import·secrets | 3 | import·secrets |
| 4 | import·sys | ||
| 4 | import·time | 5 | import·time |
| 5 | from·contextlib·import·suppress | 6 | from·contextlib·import·suppress |
| 6 | from·dataclasses·import·dataclass | 7 | from·dataclasses·import·dataclass |
| 8 | from·math·import·isfinite | ||
| 7 | from·threading·import·Event,·Thread,·current_thread | 9 | from·threading·import·Event,·Thread,·current_thread |
| 8 | from·typing·import·TYPE_CHECKING,·Literal | 10 | 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·LeaseSettingsMismatch | 13 | from·._error·import·LeaseSettingsMismatch |
| 10 | from·._identity·import·owner_is_stale | 14 | from·._identity·import·owner_is_stale |
| 11 | from·._marker·import·MarkerSoftFileLock,·OwnerMode,·OwnerRecord,·parse_marker | 15 | from·._marker·import·MarkerSoftFileLock,·OwnerMode,·OwnerRecord,·parse_marker |
| 12 | from·._soft·import·_read_lock_file | 16 | from·._soft·import·_read_lock_file |
| 13 | from·._util·import·break_lock_file,·touch | 17 | from·._util·import·break_lock_file,·touch |
| 14 | if·TYPE_CHECKING: | 18 | if·TYPE_CHECKING: |
| 15 | ····import·sys | ||
| 16 | ····from·collections.abc·import·Callable | 19 | ····from·collections.abc·import·Callable,·Mapping |
| 20 | ····from·typing·import·Unpack | ||
| 17 | ····from·._api·import·LockOptions | 21 | ····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:·str | 30 | ····lock_file:·str |
| Offset 53, 36 lines modified | Offset 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·=·None | 56 | ····token:·str·|·None·=·None |
| 55 | ····compromise:·LeaseCompromise·|·None·=·None | 57 | ····compromise:·LeaseCompromise·|·None·=·None |
| 56 | ····heartbeat:·_Heartbeat·|·None·=·None | 58 | ····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·every | 62 | ····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· | 63 | ····``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 | ···· | 65 | ····expired·holder:·it·keeps·running,·and·it·keeps·using·whatever·the·lock·protects.·Treat·the·lease·as·a·hint·about |
| 71 | ···· | 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·a | 67 | ····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·a | 70 | ····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·own | 71 | ····different·duration·raises·:class:`LeaseSettingsMismatch·<filelock.LeaseSettingsMismatch>`·rather·than·apply·its·own |
| Offset 108, 54 lines modified | Offset 97, 80 lines modified | ||
| 108 | ····_lifetime_supported:·bool·=·False | 97 | ····_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·=· | 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· | 110 | ········: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·room | 112 | ········: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``·among | 116 | ········: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·lets | 117 | ············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·would | 118 | ············:class:`AsyncSoftFileLease·<filelock.AsyncSoftFileLease>`·add·the·async·plumbing·a·fixed·signature·would |
| 129 | ············hide. | 119 | ············hide. |
| 130 | ········""" | 120 | ········""" |
| 131 | ········if· | 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 | ········ | 125 | ········heartbeat_interval·=·( |
| 135 | ············heartbeat_interval· | 126 | ············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_duration | 133 | ········self._lease_duration·=·lease_duration |
| 141 | ········self._heartbeat_interval·=·heartbeat_interval | 134 | ········self._heartbeat_interval·=·heartbeat_interval |
| Max diff block lines reached; 15268/22353 bytes (68.30%) of diff not shown. | |||
| Offset 1, 46 lines modified | Offset 1, 39 lines modified | ||
| 1 | from·__future__·import·annotations | 1 | from·__future__·import·annotations |
| 2 | import·math | 2 | import·math |
| 3 | import·os | 3 | import·os |
| 4 | import·re | ||
| 4 | from·contextlib·import·suppress | 5 | from·contextlib·import·suppress |
| 5 | from·typing·import·Final,·Literal,·NamedTuple | 6 | from·typing·import·Final,·Literal,·NamedTuple |
| 6 | from·._identity·import·host_name,·process_start_token | 7 | from·._identity·import·host_name,·owner_is_current_process,·owner_is_stale,·process_start_token |
| 7 | from·._soft·import·SoftFileLock,·_read_lock_file | 8 | from·._soft·import·SoftFileLock,·_read_lock_file,·parse_decimal |
| 8 | from·._util·import·write_all | 9 | 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·malformed | 11 | #:·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·-·1 | 14 | _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 | 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 | ····#:· | 22 | ····#:·Age-based·expiry·requires·a·lease·contract;·an·exclusive·holder·grants·none. |
| 28 | ····_owner_mode:·OwnerMode | 23 | ····_owner_mode:·OwnerMode·=·"exclusive" |
| 29 | ····@property | 24 | ····@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·1 | 28 | ········:returns:·the·published·record,·or·``None``·when·no·marker·exists·or·its·record·is·malformed·or·protocol·1 |
| Offset 59, 29 lines modified | Offset 52, 44 lines modified | ||
| 59 | ········return·None·if·(owner·:=·self._read_owner())·is·None·else·owner.pid | 52 | ········return·None·if·(owner·:=·self._read_owner())·is·None·else·owner.pid |
| 60 | ····@property | 53 | ····@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 | 57 | ········: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 | 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·lock | 64 | ········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·None | 84 | ········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 modified | Offset 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. | |||
| Offset 1, 37 lines modified | Offset 1, 52 lines modified | ||
| 1 | from·__future__·import·annotations | 1 | from·__future__·import·annotations |
| 2 | import·hashlib | ||
| 2 | import·logging | 3 | import·logging |
| 3 | import·os | 4 | import·os |
| 4 | import·pathlib | 5 | import·pathlib |
| 6 | import·shutil | ||
| 5 | import·sqlite3 | 7 | import·sqlite3 |
| 8 | import·stat | ||
| 6 | import·sys | 9 | import·sys |
| 10 | import·tempfile | ||
| 7 | import·threading | 11 | import·threading |
| 8 | import·time | 12 | import·time |
| 13 | from·collections·import·deque | ||
| 9 | from·contextlib·import·contextmanager,·suppress | 14 | 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,·cast | 17 | from·typing·import·TYPE_CHECKING,·ClassVar,·Final,·Literal,·NamedTuple,·TypeAlias,·cast |
| 11 | from·weakref·import·WeakValueDictionary | 18 | 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·Timeout | 33 | 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,·Generator | 38 | ····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.getpid | 42 | _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 modified | Offset 54, 23 lines modified | ||
| 39 | ····str·|·bytes·|·os.PathLike[str]·|·os.PathLike[bytes]·|·float·|·int·|·type[sqlite3.Connection]·|·None | 54 | ····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·-·1 | 58 | _MAX_SQLITE_TIMEOUT_MS:·Final[int]·=·2_000_000_000·-·1 |
| 44 | _UNSAFE_FORK_EXIT_STATUS:·Final[int]·=·70 | 59 | _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·=·0 | 70 | ····depth:·int·=·0 |
| 47 | _SQLITE_TRANSITION_CONTEXT:·Final·=·_SQLiteTransitionContext() | 71 | _SQLITE_TRANSITION_CONTEXT:·Final·=·_SQLiteTransitionContext() |
| Offset 130, 51 lines modified | Offset 154, 176 lines modified | ||
| 130 | ········except·OSError: | 154 | ········except·OSError: |
| 131 | ············return·None | 155 | ············return·None |
| 132 | ········return·stat_result.st_dev,·stat_result.st_ino | 156 | ········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. | |||
| Offset 2, 23 lines modified | Offset 2, 24 lines modified | ||
| 2 | import·os | 2 | import·os |
| 3 | import·stat | 3 | import·stat |
| 4 | import·sys | 4 | import·sys |
| 5 | import·time | 5 | import·time |
| 6 | from·contextlib·import·suppress | 6 | from·contextlib·import·suppress |
| 7 | from·errno·import·EACCES,·EEXIST,·EPERM | 7 | from·errno·import·EACCES,·EEXIST,·EPERM |
| 8 | from·itertools·import·islice | ||
| 8 | from·pathlib·import·Path | 9 | from·pathlib·import·Path |
| 9 | from·typing·import·Final | 10 | from·typing·import·Final |
| 10 | from·._api·import·BaseFileLock,·_raise_grouped_errors | 11 | from·._api·import·BaseFileLock,·_raise_grouped_errors |
| 11 | from·._identity·import·host_name,·owner_is_stale,·process_start_token | 12 | from·._identity·import·host_name,·owner_is_current_process,·owner_is_stale,·process_start_token |
| 12 | from·._soft_protocol·import·STRICT_SOFT_SENTINEL_RECORD | 13 | from·._soft_protocol·import·STRICT_SOFT_SENTINEL_RECORD |
| 13 | from·._util·import·break_lock_file,·ensure_directory_exists,·raise_on_not_writable_file,·write_all | 14 | from·._util·import·break_lock_file,·ensure_directory_exists,·raise_on_not_writable_file,·write_all |
| 14 | 15 | MALFORMED_LOCK_AGE_THRESHOLD:·Final[float]·=·2.0 | |
| 15 | _MAX_LOCK_FILE_SIZE:·Final[int]·=·1024 | 16 | _MAX_LOCK_FILE_SIZE:·Final[int]·=·1024 |
| 16 | _UNLINK_MAX_RETRIES:·Final[int]·=·10 | 17 | _UNLINK_MAX_RETRIES:·Final[int]·=·10 |
| 17 | _MARKER_WITH_START_TOKEN_LINE_COUNT:·Final[int]·=·3 | 18 | _MARKER_WITH_START_TOKEN_LINE_COUNT:·Final[int]·=·3 |
| 18 | class·SoftFileLock(BaseFileLock): | 19 | class·SoftFileLock(BaseFileLock): |
| 19 | ····""" | 20 | ····""" |
| Offset 44, 15 lines modified | Offset 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·=·False | 46 | ····_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·=·False | 48 | ····_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·open | 59 | ········#·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_TRUNC | 61 | ········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-nofollow | 62 | ········if·(o_nofollow·:=·getattr(os,·"O_NOFOLLOW",·None))·is·not·None:··#·pragma:·needs·o-nofollow |
| 55 | ············flags·|=·o_nofollow | 63 | ············flags·|=·o_nofollow |
| Offset 71, 42 lines modified | Offset 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·the | 83 | ········#·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·a | 84 | ········#·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·=·None | 86 | ········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 | ············raise | 97 | ············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-link | 108 | ············if·content·==·STRICT_SOFT_SENTINEL_RECORD:··#·pragma:·needs·hard-link |
| 91 | ················return | 109 | ················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·and | 113 | ················#·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· | 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 | ················return | 117 | ················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 | ····@staticmethod | 137 | ····@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-written | 139 | ········#·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·platform | 140 | ········#·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 modified | Offset 167, 144 lines modified | ||
| 128 | ········return·None | 167 | ········return·None |
| Max diff block lines reached; 11916/18419 bytes (64.69%) of diff not shown. | |||
| Offset 1, 32 lines modified | Offset 1, 36 lines modified | ||
| 1 | from·__future__·import·annotations | 1 | from·__future__·import·annotations |
| 2 | import·contextlib | 2 | import·contextlib |
| 3 | import·errno | 3 | import·errno |
| 4 | import·functools | ||
| 4 | import·os | 5 | import·os |
| 5 | import·secrets | 6 | import·secrets |
| 6 | import·stat | 7 | import·stat |
| 7 | import·sys | 8 | import·sys |
| 8 | import·tempfile | 9 | import·tempfile |
| 9 | import·time | 10 | import·time |
| 10 | from·dataclasses·import·dataclass | 11 | from·dataclasses·import·dataclass |
| 11 | from·errno·import·EACCES,·EEXIST,·ENOENT,·ENOSYS,·EPERM,·ESTALE,·EXDEV | 12 | from·errno·import·EACCES,·EEXIST,·ENOENT,·ENOSYS,·EPERM,·ESTALE,·EXDEV |
| 12 | from·pathlib·import·Path | 13 | from·pathlib·import·Path |
| 13 | from·typing·import·TYPE_CHECKING,·Final,·Literal,·cast | 14 | from·typing·import·TYPE_CHECKING,·Final,·Literal,·cast |
| 14 | from·._api·import·BaseFileLock,·_canonical,·_raise_cleanup_errors | 15 | from·._api·import·BaseFileLock,·ThreadLocalFileContext,·_canonical,·_raise_cleanup_errors |
| 15 | from·._error·import·SoftFileLockProtocolError | 16 | from·._error·import·SoftFileLockProtocolError |
| 16 | from·._identity·import·host_name,·process_start_token | 17 | 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_RECORD | 20 | from·._soft_protocol·import·STRICT_SOFT_SENTINEL_RECORD |
| 18 | from·._util·import·ensure_directory_exists,·write_all | 21 | from·._util·import·ensure_directory_exists,·write_all |
| 19 | if·TYPE_CHECKING: | 22 | if·TYPE_CHECKING: |
| 20 | ····from·collections.abc·import·Iterator | 23 | ····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]·=·1024 | 30 | _CLAIM_RECORD_LIMIT:·Final[int]·=·1024 |
| 27 | _CLAIM_NAME_PART_COUNT:·Final[int]·=·3 | 31 | _CLAIM_NAME_PART_COUNT:·Final[int]·=·3 |
| Offset 35, 14 lines modified | Offset 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]·=·32 | 40 | _PRIVATE_RECORD_RANDOM_HEX_LENGTH:·Final[int]·=·32 |
| 37 | _PRIVATE_RECORD_GRACE:·Final[float]·=·2.0 | 41 | _PRIVATE_RECORD_GRACE:·Final[float]·=·2.0 |
| 38 | _UNLINK_MAX_RETRIES:·Final[int]·=·10 | 42 | _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.5 | 44 | _CLAIM_READ_GRACE:·Final[float]·=·0.5 |
| 41 | _CLAIM_READ_RETRY:·Final[float]·=·0.002 | 45 | _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-link | 54 | #·Termux/Android·CPython·ships·without·os.link·(bionic·long·had·only·linkat),·so·the·strict·backend's·whole·hard-link |
| Offset 97, 135 lines modified | Offset 104, 184 lines modified | ||
| 97 | ····_preserve_lock_file_supported:·bool·=·True | 104 | ····_preserve_lock_file_supported:·bool·=·True |
| 98 | ····_on_acquired_supported:·bool·=·False | 105 | ····_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·rule | 106 | ····#:·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·=·False | 108 | ····_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· | 110 | ····#:·Contending·processes·each·publish·and·rescan·several·files,·so·jitter·their·retries.·Seconds.·Only·a |
| 106 | ····#:· | 111 | ····#:·poll_interval·below·this·cap·jitters;·the·default·equals·it·and·keeps·a·fixed·cadence. |
| 107 | ····_poll_backoff_cap:·float·=·0.05 | 112 | ····_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·the | 117 | ········#·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_NAME | 123 | ········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·( | 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 | ············return | 132 | ············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·errors | 135 | ········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·errors | 138 | ············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 | ············raise | 140 | ············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_director | 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 | ············raise | 146 | ············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 | ···· | 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 | ············return | 155 | ············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. | |||
| Offset 63, 78 lines modified | Offset 63, 85 lines modified | ||
| 63 | ········We·leave·the·lock·file·in·place·after·release.·Unlinking·a·locked·file·on·Unix·splits | 63 | ········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·the | 64 | ········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 | ················ | 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 | ················ | 74 | ················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·failure | 83 | ····················raise··#·contention·returns·False·from·_lock_fd_nonblocking,·so·any·raise·here·is·a·real·failure |
| 107 | ················return·fd,·exception | 84 | ················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·again | 89 | ················os.close(fd)··#·contention;·let·the·retry·loop·try·again |
| 113 | ············return·None | 90 | ············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·cleanup | 119 | ············#·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·=·None | 121 | ············identity:·tuple[int,·int]·|·None·=·None |
| 118 | ············with·suppress(OSError): | 122 | ············with·suppress(OSError): |
| 119 | ················identity·=·(fstat·:=·os.fstat(fd)).st_dev,·fstat.st_ino | 123 | ················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·pathname | 127 | ················#·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_flock | 129 | ················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·than | 139 | ············#·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()·and | 140 | ············#·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. |
| Offset 1, 25 lines modified | Offset 1, 26 lines modified | ||
| 1 | from·__future__·import·annotations | 1 | from·__future__·import·annotations |
| 2 | import·os | 2 | import·os |
| 3 | import·secrets | 3 | import·secrets |
| 4 | import·stat | 4 | import·stat |
| 5 | import·sys | 5 | import·sys |
| 6 | from·contextlib·import·suppress | ||
| 6 | from·errno·import·EACCES,·EIO,·EISDIR | 7 | from·errno·import·EACCES,·EIO,·EISDIR |
| 7 | from·pathlib·import·Path | 8 | from·pathlib·import·Path |
| 8 | from·typing·import·Final | 9 | 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· | 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 | ···· | 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 modified | Offset 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·on | 52 | ········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-zero | 53 | ····#·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·pass | 54 | ····#·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·cover | 67 | ········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·cover | 69 | ········raise·IsADirectoryError(EISDIR,·"Is·a·directory",·filename)··#·pragma:·win32·no·cover |
| Offset 70, 61 lines modified | Offset 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 | ···· | 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 | ···· | 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 | ···· | 96 | ····We·add·a·random·token·to·the·break·name·so·other·processes·cannot·guess·it·and·two·breakers·in·one·process·do·not |
| 85 | ····s | 97 | ····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· | 100 | ····:param·mtime_before:·modification·time·the·caller·saw·when·it·judged·the·lock·stale. |
| 91 | ····:param·ino_before:·inode·number· | 101 | ····:param·ino_before:·inode·number·the·caller·saw·when·it·judged·the·lock·stale. |
| 92 | ····:raises·OSError:·if·the·rename· | 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 | ········return | 106 | ········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· | 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 | 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·the | 116 | ····#·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·a | 118 | ····#·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· | 120 | ····if·_SUPPORTS_UTIME_FD:··#·pragma:·needs·utime-fd |
| 109 | ········os.utime(fd,·None) | 121 | ········os.utime(fd,·None) |
| 110 | ········return | 122 | ········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. | |||
| Offset 1, 11 lines modified | Offset 1, 12 lines modified | ||
| 1 | from·__future__·import·annotations | 1 | from·__future__·import·annotations |
| 2 | import·os | 2 | import·os |
| 3 | import·sys | 3 | import·sys |
| 4 | import·time | ||
| 4 | from·contextlib·import·suppress | 5 | from·contextlib·import·suppress |
| 5 | from·pathlib·import·Path | 6 | from·pathlib·import·Path |
| 6 | from·typing·import·Final,·cast | 7 | from·typing·import·Final,·cast |
| 7 | from·._api·import·BaseFileLock | 8 | from·._api·import·BaseFileLock |
| 8 | from·._util·import·ensure_directory_exists,·raise_on_not_writable_file | 9 | from·._util·import·ensure_directory_exists,·raise_on_not_writable_file |
| Offset 37, 22 lines modified | Offset 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·shift | 39 | ····#·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's | 40 | ····#·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]·=·0x00000001 | 42 | ····_LOCKFILE_FAIL_IMMEDIATELY:·Final[int]·=·0x00000001 |
| 42 | ····_LOCKFILE_EXCLUSIVE_LOCK:·Final[int]·=·0x00000002 | 43 | ····_LOCKFILE_EXCLUSIVE_LOCK:·Final[int]·=·0x00000002 |
| 43 | ····_ERROR_LOCK_VIOLATION:·Final[int]·=·33··#·another·handle·holds·the·byte·range | 44 | ····_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·one | 46 | ····#·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·is | 47 | ····#·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]·=·0x00000000 | 49 | ····_STATUS_SUCCESS:·Final[int]·=·0x00000000 |
| 48 | ····_STATUS_ACCESS_DENIED:·Final[int]·=·0xC0000022 | 50 | ····_STATUS_ACCESS_DENIED:·Final[int]·=·0xC0000022 |
| 49 | ····_STATUS_SHARING_VIOLATION:·Final[int]·=·0xC0000043 | 51 | ····_STATUS_SHARING_VIOLATION:·Final[int]·=·0xC0000043 |
| 50 | ····_STATUS_DELETE_PENDING:·Final[int]·=·0xC0000056 | 52 | ····_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·name | 59 | ····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·count | 61 | ············("Length",·wintypes.USHORT),··#·byte·length,·not·character·count |
| Offset 159, 17 lines modified | Offset 165, 19 lines modified | ||
| 159 | ········if·err·==·_ERROR_LOCK_VIOLATION: | 165 | ········if·err·==·_ERROR_LOCK_VIOLATION: |
| 160 | ············return·False | 166 | ············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·cover | 168 | ········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·used | 170 | ········overlapped·=·_OVERLAPPED()··#·the·same·offset·0·and·one-byte·length·the·lock·used |
| 165 | ········#· | 171 | ········if·(··#·pragma:·no·cover··#·only·an·interrupted·earlier·release·leaves·our·own·range·unlocked |
| 166 | ········ | 172 | ············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( | 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·is | 179 | ········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·lock | 180 | ········not·guaranteed·in·multi-threaded·scenarios·where·another·thread·holds·an·open·handle.·The·lock |
| Offset 231, 20 lines modified | Offset 239, 27 lines modified | ||
| 231 | ········:param·mode:·the·permission·mode;·as·``os.open``·does·on·Windows,·a·cleared·owner-write·bit·creates·the·file | 239 | ········: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-pending | 241 | ········: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·with | 243 | ········: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= | 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·None | 258 | ················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 modified | Offset 331, 9 lines modified | ||
| 316 | ········def·_release(self)·->·None: | 331 | ········def·_release(self)·->·None: |
| 317 | ············raise·NotImplementedError | 332 | ············raise·NotImplementedError |
| 318 | __all__·=·[ | 333 | __all__·=·[ |
| 319 | ····"WindowsFileLock", | 334 | ····"WindowsFileLock", |
| 335 | ····"_open_non_reparse_fd", | ||
| 320 | ] | 336 | ] |
| Offset 1, 75 lines modified | Offset 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·annotations | 2 | from·__future__·import·annotations |
| 3 | import·asyncio | 3 | import·asyncio |
| 4 | import·contextlib | 4 | import·contextlib |
| 5 | import·functools | ||
| 5 | import·logging | 6 | import·logging |
| 6 | import·os | 7 | import·os |
| 8 | import·sys | ||
| 7 | import·time | 9 | import·time |
| 10 | from·concurrent·import·futures | ||
| 8 | from·dataclasses·import·dataclass | 11 | from·dataclasses·import·dataclass,·fields |
| 9 | from·inspect·import·iscoroutinefunction | 12 | from·inspect·import·iscoroutinefunction |
| 10 | from·threading·import· | 13 | from·threading·import·RLock |
| 11 | from·typing·import·TYPE_CHECKING,·Final,·NoReturn,·TypeVar,·cast | 14 | 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·Timeout | 48 | from·._error·import·Timeout |
| 41 | from·._lease·import·SoftFileLease | 49 | from·._lease·import·SoftFileLease |
| 42 | from·._soft·import·SoftFileLock | 50 | from·._soft·import·SoftFileLock |
| 43 | from·._strict·import·StrictSoftFileLock | 51 | from·._strict·import·StrictSoftFileLock |
| 44 | from·._unix·import·UnixFileLock | 52 | from·._unix·import·UnixFileLock |
| 45 | from·._windows·import·WindowsFileLock | 53 | from·._windows·import·WindowsFileLock |
| 46 | if·TYPE_CHECKING: | 54 | if·TYPE_CHECKING: |
| 47 | ····import·sys | ||
| 48 | ····from·collections.abc·import·Awaitable,·Callable,·Coroutine,·Hashable | 55 | ····from·collections.abc·import·Awaitable,·Callable,·Coroutine,·Hashable,·Mapping |
| 49 | ····from·concurrent·import·futures | ||
| 50 | ····from·types·import·TracebackType | 56 | ····from·types·import·TracebackType |
| 51 | ····if·sys.version_info·>=·(3,·11):··#·pragma:·no·cover·(py311+) | ||
| 52 | ···· | 57 | ····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·parameters | 67 | ····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·constructed | 68 | ········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 modified | Offset 163, 20 lines modified | ||
| 159 | ········:param·lock_file:·path·to·the·file | 163 | ········: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·the | 164 | ········: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·a | 165 | ············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·and | 167 | ········: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·to | 169 | ········: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`` | 170 | ············``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·change | 172 | ············``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·supplied | 173 | ············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 | ············ | 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·not | 176 | ········: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·lock | 177 | ········: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·the | 178 | ············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·value | 180 | ········: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·delete | 182 | ········:param·lifetime:·for·:class:`AsyncSoftFileLock`,·the·age·in·seconds·after·which·a·waiting·process·may·delete |
| Offset 193, 42 lines modified | Offset 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·lock | 199 | ········: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·before | 200 | ············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·the | 201 | ············: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:· | 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_local | 211 | ········self._is_thread_local·=·thread_local |
| 206 | ········self._is_singleton·=·is_singleton | 212 | ········self._is_singleton·=·is_singleton |
| 207 | ········self._context_error_policy·=·context_error_policy··#·already·validated·by·the·metaclass | 213 | ········self._context_error_policy·=·context_error_policy··#·already·validated·by·the·metaclass |
| 208 | ········self._close_error_policy·=·close_error_policy··#·already·validated·by·the·metaclass | 214 | ········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. | |||
| Offset 14, 11 lines modified | Offset 14, 11 lines modified | ||
| 14 | version:·str | 14 | version:·str |
| 15 | __version__:·str | 15 | __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·|·None | 18 | commit_id:·str·|·None |
| 19 | __commit_id__:·str·|·None | 19 | __commit_id__:·str·|·None |
| 20 | __version__·=·version·=·' | 20 | __version__·=·version·=·'4.1.1' |
| 21 | __version_tuple__·=·version_tuple·=·( | 21 | __version_tuple__·=·version_tuple·=·(4,·1,·1) |
| 22 | __commit_id__·=·commit_id·=·None | 22 | __commit_id__·=·commit_id·=·None |
| Offset 1, 8 lines modified | Offset 1, 8 lines modified | ||
| 1 | """Cross-process·and·cross-host·reader/writer·lock·o | 1 | """Cross-process·and·cross-host·reader/writer·lock·over·a·generation·log·of·immutable·snapshots.""" |
| 2 | from·__future__·import·annotations | 2 | from·__future__·import·annotations |
| 3 | from·._async·import·AsyncAcquireSoftReadWriteReturnProxy,·AsyncSoftReadWriteLock | 3 | from·._async·import·AsyncAcquireSoftReadWriteReturnProxy,·AsyncSoftReadWriteLock |
| 4 | from·._sync·import·SoftReadWriteLock | 4 | from·._sync·import·SoftReadWriteLock |
| 5 | __all__·=·[ | 5 | __all__·=·[ |
| Offset 2, 42 lines modified | Offset 2, 60 lines modified | ||
| 2 | from·__future__·import·annotations | 2 | from·__future__·import·annotations |
| 3 | import·asyncio | 3 | import·asyncio |
| 4 | import·functools | 4 | import·functools |
| 5 | import·os | 5 | import·os |
| 6 | from·contextlib·import·asynccontextmanager | 6 | from·contextlib·import·asynccontextmanager |
| 7 | from·typing·import·TYPE_CHECKING,·ParamSpec,·TypeVar | 7 | 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·SoftReadWriteLock | 17 | from·._sync·import·SoftReadWriteLock |
| 9 | if·TYPE_CHECKING: | 18 | if·TYPE_CHECKING: |
| 10 | ····from·collections.abc·import·AsyncGenerator,·Callable | 19 | ····from·collections.abc·import·AsyncGenerator,·Callable |
| 11 | ····from·concurrent·import·futures | 20 | ····from·concurrent·import·futures |
| 12 | ····from·types·import·TracebackType | 21 | ····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()``.· | 29 | ····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 | ····T | 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;· | 34 | ····: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·indefinitely | 35 | ····:param·timeout:·maximum·wait·time·in·seconds;·``-1``·means·block·indefinitely |
| 23 | ····:param·blocking:·if·``False``,·raise·:class:`~filelock.Timeout`·immediately·on·contention | 36 | ····:param·blocking:·if·``False``,·raise·:class:`~filelock.Timeout`·immediately·on·contention |
| 24 | ····:param·is_singleton:·if·``True``,·reuse·existing·:class:`SoftReadWriteLock`·instances·per·resolved·path | 37 | ····:param·is_singleton:·if·``True``,·reuse·existing·:class:`SoftReadWriteLock`·instances·per·resolved·path |
| 25 | ····:param·heartbeat_interval:·seconds·between·heartbeat·refreshes;·default·30·s | 38 | ····:param·heartbeat_interval:·seconds·between·heartbeat·refreshes;·default·30·s |
| 26 | ····:param·stale_threshold:·seconds· | 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·s | 41 | ····: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·loop | 44 | ····: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·executor | 45 | ····:param·executor:·executor·for·``run_in_executor``;·``None``·uses·the·default·executor |
| 30 | ····..·versionadded::·3.27.0 | 46 | ····..·versionadded::·3.27.0 |
| 31 | ····""" | 47 | ····""" |
| Offset 47, 27 lines modified | Offset 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·=·loop | 88 | ········self._loop·=·loop |
| 68 | ········self._executor·=·executor | 89 | ········self._executor·=·executor |
| 69 | ····@property | 90 | ····@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_file | 93 | ········return·self._lock.lock_file |
| Offset 79, 14 lines modified | Offset 100, 24 lines modified | ||
| 79 | ····@property | 100 | ····@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.blocking | 103 | ········return·self._lock.blocking |
| 83 | ····@property | 104 | ····@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._loop | 115 | ········return·self._loop |
| 87 | ····@property | 116 | ····@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 modified | Offset 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·default | 130 | ········: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·default | 131 | ········:param·blocking:·if·``False``,·raise·:class:`~filelock.Timeout`·immediately;·``None``·uses·the·instance·default |
| 101 | ········:raises·RuntimeError:·if· | 132 | ········:raises·RuntimeError:·if·the·calling·task·already·holds·the·write·lock |
| 102 | ········:raises·Timeout:·if·the·lock·cannot·be·acquired·within·*timeout*·seconds | 133 | ········: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. | |||
| Offset 1, 88 lines modified | Offset 1, 82 lines modified | ||
| 1 | """Cross-process·and·cross-host·reader/writer·lock· | 1 | """Cross-process·and·cross-host·reader/writer·lock·over·a·generation·log·of·immutable·snapshots.""" |
| 2 | from·__future__·import·annotations | 2 | from·__future__·import·annotations |
| 3 | import·atexit | 3 | import·atexit |
| 4 | import·hmac | ||
| 5 | import·os | 4 | import·os |
| 6 | import·re | ||
| 7 | import·secrets | ||
| 8 | import·socket | ||
| 9 | import·stat | ||
| 10 | import·sys | ||
| 11 | import·threading | 5 | import·threading |
| 12 | import·time | 6 | import·time |
| 13 | import·uuid | ||
| 14 | from·contextlib·import·c | 7 | from·contextlib·import·contextmanager,·suppress |
| 15 | from·dataclasses·import·dataclass | 8 | from·dataclasses·import·dataclass |
| 16 | from· | 9 | from·math·import·isfinite |
| 17 | from·typing·import·TYPE_CHECKING,·Final | 10 | from·typing·import·TYPE_CHECKING,·Final |
| 18 | from·weakref·import·WeakValueDictionary | 11 | 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 | ····_ | 19 | ····_resolve_read_write_timeout, |
| 20 | ····_seconds, | ||
| 21 | ····_timeout_behavior, | ||
| 28 | ) | 22 | ) |
| 29 | from·filelock._error·import·Timeout | 23 | from·filelock._error·import·Timeout |
| 30 | from·filelock._soft·import·SoftFileLock | ||
| 31 | from·filelock._ | 24 | 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,·Generator | 28 | ····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[ | 32 | _SINGLETONS_UNDER_CONSTRUCTION:·Final[set[str]]·=·set() |
| 45 | class·_SoftRWMeta(type): | 33 | class·_SoftRWMeta(type): |
| 46 | ····_instances:·WeakValueDictionary[ | 34 | ····_instances:·WeakValueDictionary[str,·SoftReadWriteLock] |
| 47 | ····_instances_lock:·threading.RLock | 35 | ····_instances_lock:·threading.RLock |
| 48 | ····def·__call__(··#·ruff:ignore[too-many-arguments]··#·forwards·the·public·constructor's·documented·parameters | 36 | ····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·=· | 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·fork | 68 | ················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 modified | Offset 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·fork | 97 | ················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]·=·instance | 100 | ················cls._instances[normalized]·=·instance |
| 101 | ············elif·( | ||
| 102 | ················_timeout_behavior(instance.timeout,·any_negative=False) | ||
| 103 | ················!=·_timeout_behavior(timeout,·any_negative=False) | ||
| 106 | ············ | 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. | |||
| Offset 1, 13 lines modified | Offset 1, 13 lines modified | ||
| 1 | #Copyright·ReportLab·Europe·Ltd.·2000-2026 | 1 | #Copyright·ReportLab·Europe·Ltd.·2000-2026 |
| 2 | #see·license.txt·for·license·details | 2 | #see·license.txt·for·license·details |
| 3 | __doc__="""The·Reportlab·PDF·generation·library.""" | 3 | __doc__="""The·Reportlab·PDF·generation·library.""" |
| 4 | Version·=·"5.0. | 4 | Version·=·"5.0.1" |
| 5 | __version__=Version | 5 | __version__=Version |
| 6 | __date__='20260 | 6 | __date__='20260820' |
| 7 | import·sys,·os | 7 | 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__ |
| Offset 291, 15 lines modified | Offset 291, 15 lines modified | ||
| 291 | ····an·A4·page·with·a·title·above·it·-·possibly·overflowing | 291 | ····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'+x | 295 | ········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)) |
| Offset 5, 14 lines modified | Offset 5, 19 lines modified | ||
| 5 | #hopefully·we·are·standing·on·giants'·shoulders | 5 | #hopefully·we·are·standing·on·giants'·shoulders |
| 6 | import·sys,·os,·ast,·re,·weakref,·time,·copy,·math,·types | 6 | 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·textwrap | 15 | import·textwrap |
| 12 | class·BadCode(ValueError): | 16 | class·BadCode(ValueError): |
| 13 | » pass | 17 | » 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 modified | Offset 920, 26 lines modified | ||
| 915 | » » #these·are·used·in·the·tree·visitor | 920 | » » #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·builtins | 936 | » » #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 modified | Offset 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.start | 1092 | » » » » start·=·a.start |
| 1082 | » » » » stop·=·a.stop | 1093 | » » » » stop·=·a.stop |
| 1083 | » » » » if·start·is·None: | 1094 | » » » » if·start·is·None: |
| Offset 1090, 14 lines modified | Offset 1102, 25 lines modified | ||
| 1090 | » » » » » v·=·obj[start:stop] | 1102 | » » » » » v·=·obj[start:stop] |
| 1091 | » » » return·v | 1103 | » » » 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__·=·5 | 1118 | » __rl_tmax__·=·5 |
| 1097 | » __rl_max_len__·=·100000 | 1119 | » __rl_max_len__·=·100000 |
| 1098 | » __rl_max_pow_digits__·=·100 | 1120 | » __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__): |
| Offset 467, 21 lines modified | Offset 467, 16 lines modified | ||
| 467 | ········#the·dirname(reportlab.__file__)·or·is·relative | 467 | ········#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,·urlparse | 472 | from·urllib.parse·import·unquote,·urlparse |
| 473 | 473 | _tHaS·=·{}··#cache·for·(trustedHosts,trustedSchemes) | |
| 474 | def·rlUrlRead( | 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·because | 476 | ····#copied·here·from·urllib.URLopener.open_data·because |
| 481 | ····#·1)·they·want·to·remove·it | 477 | ····#·1)·they·want·to·remove·it |
| 482 | ····#·2)·the·existing·one·is·borken | 478 | ····#·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·data | 481 | ········#·ignore·POSTed·data |
| Offset 505, 49 lines modified | Offset 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·data | 506 | ········return·data |
| 512 | ····from·reportlab.rl_config·import·trustedHosts,·trustedSchemes | ||
| 513 | ····i | 507 | ····import·socket |
| 508 | ····from·urllib.request·import·OpenerDirector,·build_opener,·Request | ||
| 514 | ···· | 509 | ····import·re,·fnmatch |
| 515 | ···· | 510 | ····def·xre(s): |
| 516 | ········ | 511 | ········s·=·fnmatch.translate(s) |
| 517 | ········ | 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 | ········ | 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 | ································ | 543 | ································)) |
| 521 | ····def·open_for_read(name,mode='b'): | ||
| 522 | ········'''attempt·to·open·a·file·or·URL·for·reading''' | ||
| 523 | ········ | 544 | ················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 | ············ | 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 | ············ | 558 | ············raise·IOError(f'Cannot·open·resource·{url!r}') |
| 544 | ····globals()[' | 559 | ····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 modified | Offset 675, 18 lines modified | ||
| 652 | ········else: | 675 | ········else: |
| 653 | ············try: | 676 | ············try: |
| 654 | ················from·reportlab.rl_config·import·imageReaderFlags | 677 | ················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. | |||
| Offset 1304, 15 lines modified | Offset 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(' | 1311 | ············s·=·s.encode('latin1')··#this·is·what·pdfdoc.py·uses;·could·not·detect·need·in·tests |
| 1312 | ········return·s | 1312 | ········return·s |
| 1313 | ····def·setPageSize(self,·size): | 1313 | ····def·setPageSize(self,·size): |
| 1314 | ········"""accepts·a·2-tuple·in·points·for·paper·size·for·this | 1314 | ········"""accepts·a·2-tuple·in·points·for·paper·size·for·this |
| 1315 | ········and·subsequent·pages""" | 1315 | ········and·subsequent·pages""" |
| 1316 | ········self._pagesize·=·size | 1316 | ········self._pagesize·=·size |
| 1317 | ········self._make_preamble() | 1317 | ········self._make_preamble() |
| Offset 26, 33 lines modified | Offset 26, 35 lines modified | ||
| 26 | SOFTWARE. | 26 | SOFTWARE. |
| 27 | """ | 27 | """ |
| 28 | from·__future__·import·annotations | 28 | from·__future__·import·annotations |
| 29 | from·.__meta__·import·__version__,·__version_info__··#·noqa:·F401 | 29 | from·.__meta__·import·__version__,·__version_info__··#·noqa:·F401 |
| 30 | from·.·import·css_parser·as·cp | 30 | from·.·import·css_parser·as·cp |
| 31 | from·.·import·css_match·as·cm | 31 | from·.·import·css_match·as·cm |
| 32 | from·.·import·css_types·as·ct | 32 | from·.·import·css_types·as·ct |
| 33 | from·.util·import·DEBUG,·SelectorSyntaxError··#·noqa:·F401 | 33 | from·.util·import·DEBUG,·NOCACHE,·NOSTRICT,·SelectorSyntaxError··#·noqa:·F401 |
| 34 | import·bs4 | 34 | import·bs4 |
| 35 | from·typing·import·Any,·Iterator,·Iterable | 35 | 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.SoupSieve | 40 | SoupSieve·=·cm.SoupSieve |
| 41 | CustomSelectors·=·ct.CustomSelectors | ||
| 42 | def·compile(··#·noqa:·A001 | 42 | 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:· | 47 | ····custom:·Mapping[str,·str·|·ct.SelectorList]·|·None·=·None, |
| 48 | ····ignore:·Iterable[str]·|·None·=·None, | ||
| 49 | ····max_selectors:·int·=·cp.SELECTOR_LIMIT, | ||
| 48 | ····**kwargs:·Any | 50 | ····**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 modified | Offset 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·pattern | 65 | ········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( | 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 | ········flags | 73 | ········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 modified | Offset 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:· | 90 | ····custom:·Mapping[str,·str·|·ct.SelectorList]·|·None·=·None, |
| 91 | ····ignore:·Iterable[str]·|·None·=·None, | ||
| 92 | ····max_selectors:·int·=·cp.SELECTOR_LIMIT, | ||
| 85 | ····**kwargs:·Any | 93 | ····**kwargs:·Any |
| 86 | )·->·bs4.Tag·|·None: | 94 | )·->·bs4.Tag·|·None: |
| 87 | ····"""Match·closest·ancestor.""" | 95 | ····"""Match·closest·ancestor.""" |
| 88 | ····return·compile( | 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:· | 111 | ····custom:·Mapping[str,·str·|·ct.SelectorList]·|·None·=·None, |
| 112 | ····ignore:·Iterable[str]·|·None·=·None, | ||
| 113 | ····max_selectors:·int·=·cp.SELECTOR_LIMIT, | ||
| 96 | ····**kwargs:·Any | 114 | ····**kwargs:·Any |
| 97 | )·->·bool: | 115 | )·->·bool: |
| 98 | ····"""Match·node.""" | 116 | ····"""Match·node.""" |
| 99 | ····return·compile( | 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:·A001 | 126 | 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:· | 132 | ····custom:·Mapping[str,·str·|·ct.SelectorList]·|·None·=·None, |
| 133 | ····ignore:·Iterable[str]·|·None·=·None, | ||
| 134 | ····max_selectors:·int·=·cp.SELECTOR_LIMIT, | ||
| 107 | ····**kwargs:·Any | 135 | ····**kwargs:·Any |
| 108 | )·->·list[bs4.Tag]: | 136 | )·->·list[bs4.Tag]: |
| 109 | ····"""Filter·list·of·nodes.""" | 137 | ····"""Filter·list·of·nodes.""" |
| 110 | ····return·compile( | 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. | |||
| Offset 189, 9 lines modified | Offset 189, 9 lines modified | ||
| 189 | ····#·Handle·post | 189 | ····#·Handle·post |
| 190 | ····post·=·int(m.group('post'))·if·m.group('post')·else·0 | 190 | ····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( | 192 | __version_info__·=·Version(3,·0,·3,·"final") |
| 193 | __version__·=·__version_info__._get_canonical() | 193 | __version__·=·__version_info__._get_canonical() |
| Offset 1, 16 lines modified | Offset 1, 28 lines modified | ||
| 1 | """CSS·matcher.""" | 1 | """CSS·matcher.""" |
| 2 | from·__future__·import·annotations | 2 | from·__future__·import·annotations |
| 3 | from·datetime·import·datetime | 3 | from·datetime·import·datetime |
| 4 | from·collections.abc·import·Hashable | ||
| 4 | from·.·import·util | 5 | from·.·import·util |
| 5 | import·re | 6 | import·re |
| 6 | from·.·import·css_types·as·ct | 7 | from·.·import·css_types·as·ct |
| 7 | import·unicodedata | 8 | import·unicodedata |
| 8 | import·bs4 | 9 | import·bs4 |
| 9 | from·typing·import· | 10 | 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 | #·Relationships | 25 | #·Relationships |
| Offset 21, 14 lines modified | Offset 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_RTL | 45 | DIR_FLAGS·=·ct.SEL_DIR_LTR·|·ct.SEL_DIR_RTL |
| 29 | RANGES·=·ct.SEL_IN_RANGE·|·ct.SEL_OUT_OF_RANGE | 46 | RANGES·=·ct.SEL_IN_RANGE·|·ct.SEL_OUT_OF_RANGE |
| 30 | DIR_MAP·=·{ | 47 | DIR_MAP·=·{ |
| Offset 52, 32 lines modified | Offset 70, 19 lines modified | ||
| 52 | SHORT_MONTH·=·30 | 70 | SHORT_MONTH·=·30 |
| 53 | LONG_MONTH·=·31 | 71 | LONG_MONTH·=·31 |
| 54 | FEB_MONTH·=·28 | 72 | FEB_MONTH·=·28 |
| 55 | FEB_LEAP_MONTH·=·29 | 73 | FEB_LEAP_MONTH·=·29 |
| 56 | DAYS_IN_WEEK·=·7 | 74 | 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 | ···· | 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 | ····@classmethod | 81 | ····@classmethod |
| 73 | ····def·assert_valid_input(cls,·tag:·Any)·->·None: | 82 | ····def·assert_valid_input(cls,·tag:·Any)·->·None: |
| Offset 125, 20 lines modified | Offset 130, 14 lines modified | ||
| 125 | ····@classmethod | 130 | ····@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 | ····@staticmethod | 134 | ····@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 modified | Offset 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·=·False | 179 | ········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) | 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. | |||
| Offset 3, 19 lines modified | Offset 3, 21 lines modified | ||
| 3 | import·re | 3 | import·re |
| 4 | from·functools·import·lru_cache | 4 | from·functools·import·lru_cache |
| 5 | from·.·import·util | 5 | from·.·import·util |
| 6 | from·.·import·css_match·as·cm | 6 | from·.·import·css_match·as·cm |
| 7 | from·.·import·css_types·as·ct | 7 | from·.·import·css_types·as·ct |
| 8 | from·.util·import·SelectorSyntaxError | 8 | from·.util·import·SelectorSyntaxError |
| 9 | import·warnings | 9 | import·warnings |
| 10 | from·typing·import·Match,·Any,·Iterator,·cast | 10 | from·typing·import·Match,·Any,·Callable,·Iterator,·Iterable,·Mapping,·cast |
| 11 | from·dataclasses·import·dataclass | 11 | from·dataclasses·import·dataclass |
| 12 | from·collections·import·UserDict | 12 | from·collections·import·UserDict |
| 13 | import·threading | 13 | 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·=·0xFFFD | 17 | UNICODE_REPLACEMENT_CHAR·=·0xFFFD |
| 17 | SELECTOR_LIMIT·=·8192 | 18 | SELECTOR_LIMIT·=·8192 |
| Offset 105, 91 lines modified | Offset 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_SPECIAL | 109 | PSEUDO_SUPPORTED·=·PSEUDO_SIMPLE·|·PSEUDO_SIMPLE_NO_MATCH·|·PSEUDO_COMPLEX·|·PSEUDO_COMPLEX_NO_MATCH·|·PSEUDO_SPECIAL |
| 108 | #·Sub-patterns·parts | 110 | #·Sub-patterns·parts |
| 109 | #·Whitespace | 111 | #·Whitespace |
| 110 | NEWLINE·=·r'(? | 112 | NEWLINE·=·r'(?>\r\n|[\n\f\r])' |
| 111 | WS·=·fr'(?:[·\t]|{NEWLINE})' | 113 | WS·=·fr'(?:[·\t]|{NEWLINE})' |
| 112 | #·Comments | 114 | #·Comments |
| 113 | COMMENTS·=·r'(?:/\*(?:[^*]|\*(?!/))*\*/)' | 115 | COMMENTS·=·r'(?:/\*(?:[^*]|\*(?!/))*+\*/)' |
| 114 | #·Whitespace·with·comments·included | 116 | #·Whitespace·with·comments·included |
| 115 | WSC·=·fr'(?:{WS}|{COMMENTS})' | 117 | WSC·=·fr'(?:{WS}|{COMMENTS})' |
| 116 | #·CSS·escapes | 118 | #·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}?| | 120 | CSS_STRING_ESCAPES·=·fr'(?:\\(?:[a-f0-9]{{1,6}}+{WS}?+|{NEWLINE}|[^\r\n\f]|$))' |
| 119 | #·CSS·Identifier | 121 | #·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`·content | 126 | #·`nth`·content |
| 125 | NTH·=·fr' | 127 | NTH·=·fr'[-+]?+(?:[0-9]++n?+|n)(?:(?<=n){WSC}*+[-+]{WSC}*+[0-9]++)?+' |
| 126 | #·Value:·quoted·string·or·identifier | 128 | #·Value:·quoted·string·or·identifier |
| 127 | VALUE·=·fr''' | 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]))?)? | 135 | ATTR·=·fr'(?:{WSC}*+(?P<cmp>[!~^|*$]?+=){WSC}*+(?P<value>{VALUE})(?:{WSC}*+(?P<case>[is]))?+)?+' |
| 130 | #·Selector·patterns | 136 | #·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'{ | 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·expressions | 177 | #·Regular·expressions |
| 172 | #·CSS·escape·pattern | 178 | #·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`·specifiers | 181 | #·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·checks | 185 | #·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]|(? | 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 | #·Constants | 193 | #·Constants |
| 186 | #·List·split·token | 194 | #·List·split·token |
| 187 | COMMA_COMBINATOR·=·',' | 195 | COMMA_COMBINATOR·=·',' |
| 188 | #·Relation·token·for·descendant | 196 | #·Relation·token·for·descendant |
| 189 | WS_COMBINATOR·=·"·" | 197 | WS_COMBINATOR·=·"·" |
| Offset 211, 78 lines modified | Offset 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. | |||
| Offset 1, 40 lines modified | Offset 1, 58 lines modified | ||
| 1 | """CSS·selector·structure·items.""" | 1 | """CSS·selector·structure·items.""" |
| 2 | from·__future__·import·annotations | 2 | from·__future__·import·annotations |
| 3 | from·enum·import·Enum | ||
| 3 | import·copyreg | 4 | import·copyreg |
| 4 | from·.pretty·import·pretty | 5 | from·.pretty·import·pretty |
| 5 | from·typing·import·Any,·Iterator,· | 6 | 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·=·0x1 | 19 | SEL_EMPTY·=·0x1 |
| 19 | SEL_ROOT·=·0x2 | 20 | SEL_ROOT·=·0x2 |
| 20 | SEL_DEFAULT·=·0x4 | 21 | SEL_DEFAULT·=·0x4 |
| 21 | SEL_INDETERMINATE·=·0x8 | 22 | SEL_INDETERMINATE·=·0x8 |
| 22 | SEL_SCOPE·=·0x10 | 23 | SEL_SCOPE·=·0x10 |
| 23 | SEL_DIR_LTR·=·0x20 | 24 | SEL_DIR_LTR·=·0x20 |
| 24 | SEL_DIR_RTL·=·0x40 | 25 | SEL_DIR_RTL·=·0x40 |
| 25 | SEL_IN_RANGE·=·0x80 | 26 | SEL_IN_RANGE·=·0x80 |
| 26 | SEL_OUT_OF_RANGE·=·0x100 | 27 | SEL_OUT_OF_RANGE·=·0x100 |
| 27 | SEL_DEFINED·=·0x200 | 28 | SEL_DEFINED·=·0x200 |
| 28 | SEL_PLACEHOLDER_SHOWN·=·0x400 | 29 | 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:·int | 44 | ····_hash:·int |
| Offset 51, 139 lines modified | Offset 69, 100 lines modified | ||
| 51 | ····@classmethod | 69 | ····@classmethod |
| 52 | ····def·__base__(cls)·->·type[Immutable]: | 70 | ····def·__base__(cls)·->·type[Immutable]: |
| 53 | ········"""Get·base·class.""" | 71 | ········"""Get·base·class.""" |
| 54 | ········return·cls | 72 | ········return·cls |
| 55 | ····def·__eq__(self,·other:·Any)·->·bool: | 73 | ····def·__eq__(self,·other:·Any)·->·bool: |
| 56 | ········""" | 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 | ········""" | 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._hash | 105 | ········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·cover | 109 | ····def·__repr__(self)·->·str:··#·pragma:·no·cover |
| 74 | ········""" | 110 | ········""" |
| 111 | ········Build·a·representation·without·using·recursion. | ||
| 75 | ········r·=·',·'.join([f"{k}={getattr(self,·k)!r}"·for·k·in·self.__slots__[:-1]]) | ||
| 76 | ········ | 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. | |||
| Offset 2, 14 lines modified | Offset 2, 16 lines modified | ||
| 2 | from·__future__·import·annotations | 2 | from·__future__·import·annotations |
| 3 | from·functools·import·wraps,·lru_cache | 3 | from·functools·import·wraps,·lru_cache |
| 4 | import·warnings | 4 | import·warnings |
| 5 | import·re | 5 | import·re |
| 6 | from·typing·import·Callable,·Any | 6 | from·typing·import·Callable,·Any |
| 7 | DEBUG·=·0x00001 | 7 | 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 modified | Offset 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·=·0 | 82 | ····last·=·0 |
| 81 | ····current_line·=·1 | 83 | ····current_line·=·1 |
| 82 | ····col·=·1 | 84 | ····col·=·1 |
| 83 | ····text | 85 | ····text:·list[str]·=·[] |
| 84 | ····line·=·1 | 86 | ····line·=·1 |
| 85 | ····offset | 87 | ····offset:·int·|·None·=·None |
| 86 | ····#·Split·pattern·by·newline·and·handle·the·text·before·the·newline | 88 | ····#·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·=·-1 | 93 | ············offset·=·-1 |
| Offset 24, 15 lines modified | Offset 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( | 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 modified | Offset 44, 17 lines modified | ||
| 40 | ············-·%(dirname)s:·Directory·of·input·file | 44 | ············-·%(dirname)s:·Directory·of·input·file |
| 41 | ············-·%(basename)s:·Full·filename·with·extension | 45 | ············-·%(basename)s:·Full·filename·with·extension |
| 42 | ············-·%(base)s:·Filename·without·extension | 46 | ············-·%(base)s:·Filename·without·extension |
| 43 | ············-·%(ext)s:·File·extension | 47 | ············-·%(ext)s:·File·extension |
| 44 | ············-·%(now)s:·Current·datetime·object | 48 | ············-·%(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 modified | Offset 92, 15 lines modified | ||
| 85 | ····#·allow·classic·%%(name)s·notation | 92 | ····#·allow·classic·%%(name)s·notation |
| 86 | ····out_path·=·out_pattern·%·file_info | 93 | ····out_path·=·out_pattern·%·file_info |
| 87 | ····#·allow·also·newer·{name}·notation | 94 | ····#·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·file | 96 | ····#·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 | ········raise | 101 | ········raise |
| 95 | ····#·save·converted·file | 102 | ····#·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 modified | Offset 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 modified | Offset 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 | ········ | 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) | ||
| Offset 11, 15 lines modified | Offset 11, 15 lines modified | ||
| 11 | -·Automatic·font·file·detection·and·registration | 11 | -·Automatic·font·file·detection·and·registration |
| 12 | """ | 12 | """ |
| 13 | import·os | 13 | import·os |
| 14 | import·shutil | 14 | import·shutil |
| 15 | import·subprocess | 15 | import·subprocess |
| 16 | import·sys | 16 | import·sys |
| 17 | from·typing·import· | 17 | from·typing·import·Optional,·Union |
| 18 | from·reportlab.pdfbase.pdfmetrics·import·registerFont | 18 | from·reportlab.pdfbase.pdfmetrics·import·registerFont |
| 19 | from·reportlab.pdfbase.ttfonts·import·TTFError,·TTFont | 19 | 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 modified | Offset 67, 16 lines modified | ||
| 67 | ················'rlgFont':·'reportlab_font_name', | 67 | ················'rlgFont':·'reportlab_font_name', |
| 68 | ················'exact':·True/False | 68 | ················'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:· | 73 | ········self._map:·dict[str,·dict[str,·Union[str,·bool,·int]]]·=·{} |
| 74 | ········self._family_index:· | 74 | ········self._family_index:·dict[str,·str]·=·{}··#·lowercase·family·→·canonical·family |
| 75 | ········self.register_default_fonts() | 75 | ········self.register_default_fonts() |
| 76 | ····@staticmethod | 76 | ····@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 modified | Offset 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·filename | 153 | ········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 | ····)·->· | 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·that | 158 | ········Uses·the·system's·fontconfig·utility·to·locate·and·register·fonts·that |
| 159 | ········match·the·given·specifications.·This·provides·access·to·system-installed | 159 | ········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 modified | Offset 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 | ····)·->· | 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·ReportLab | 358 | ········1.·Registering·a·custom·TrueType·font·file·with·ReportLab |
| 359 | ········2.·Creating·a·mapping·from·SVG·font·specifications·to·existing·ReportLab·fonts | 359 | ········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 modified | Offset 422, 15 lines modified | ||
| 422 | ················return·NOT_FOUND | 422 | ················return·NOT_FOUND |
| 423 | ········#·If·we·reach·here,·no·registration·was·possible | 423 | ········#·If·we·reach·here,·no·registration·was·possible |
| 424 | ········return·NOT_FOUND | 424 | ········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 | ····)·->· | 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-based | 430 | ········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 modified | Offset 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 | )·->· | 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 modified | Offset 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 | )·->· | 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. |
| Offset 18, 40 lines modified | Offset 18, 48 lines modified | ||
| 18 | ········$·python·-m·svglib·foo.svg | 18 | ········$·python·-m·svglib·foo.svg |
| 19 | """ | 19 | """ |
| 20 | import·base64 | 20 | import·base64 |
| 21 | import·copy | 21 | import·copy |
| 22 | import·gzip | 22 | import·gzip |
| 23 | import·itertools | 23 | import·itertools |
| 24 | import·locale | ||
| 25 | import·logging | 24 | import·logging |
| 26 | import·os | 25 | import·os |
| 27 | import·pathlib | 26 | import·pathlib |
| 28 | import·re | 27 | import·re |
| 29 | import·shlex | 28 | import·shlex |
| 30 | import·shutil | 29 | import·shutil |
| 31 | import·sys | ||
| 32 | from·collections·import·defaultdict,·namedtuple | 30 | from·collections·import·defaultdict,·namedtuple |
| 33 | from·io·import·BytesIO | 31 | from·io·import·BytesIO |
| 34 | from·typing·import· | 32 | from·typing·import·( |
| 33 | ····Any, | ||
| 34 | ····BinaryIO, | ||
| 35 | ····Optional, | ||
| 36 | ····TextIO, | ||
| 37 | ····TypedDict, | ||
| 38 | ····Union, | ||
| 39 | ····cast, | ||
| 40 | ) | ||
| 35 | from·PIL·import·Image·as·PILImage | 41 | 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·colors | 61 | from·reportlab.lib·import·colors |
| 54 | from·reportlab.lib.units·import·toLength | 62 | from·reportlab.lib.units·import·toLength |
| 55 | from·reportlab.pdfbase.pdfmetrics·import·stringWidth | 63 | from·reportlab.pdfbase.pdfmetrics·import·stringWidth |
| Offset 89, 14 lines modified | Offset 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.75 | 101 | 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·has | 130 | ····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·prevent | 131 | ····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 modified | Offset 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 | )·->· | 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·font | 166 | ····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 modified | Offset 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 | )·->· | 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·font | 187 | ····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. | |||
| Offset 11, 20 lines modified | Offset 11, 20 lines modified | ||
| 11 | -·Elliptical·arc·processing·functions | 11 | -·Elliptical·arc·processing·functions |
| 12 | -·Vector·mathematics·helpers | 12 | -·Vector·mathematics·helpers |
| 13 | -·String·parsing·utilities·for·SVG·attributes | 13 | -·String·parsing·utilities·for·SVG·attributes |
| 14 | """ | 14 | """ |
| 15 | import·re | 15 | import·re |
| 16 | from·math·import·acos,·ceil,·copysign,·cos,·degrees,·fabs,·hypot,·radians,·sin,·sqrt | 16 | from·math·import·acos,·ceil,·copysign,·cos,·degrees,·fabs,·hypot,·radians,·sin,·sqrt |
| 17 | from·typing·import· | 17 | from·typing·import·Union,·cast |
| 18 | from·reportlab.graphics.shapes·import·mmult,·rotate,·transformPoint,·translate | 18 | from·reportlab.graphics.shapes·import·mmult,·rotate,·transformPoint,·translate |
| 19 | def·split_floats(op:·str,·min_num:·int,·value:·str)·->· | 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·the | 21 | ····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·subsequent | 22 | ····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 modified | Offset 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·seq | 53 | ········if·seq |
| 54 | ····] | 54 | ····] |
| 55 | ····res:· | 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( | 59 | ········res.extend([op,·cast(list[float],·list(floats[i·:·i·+·min_num]))]) |
| 60 | ····return·res | 60 | ····return·res |
| 61 | def·split_arc_values(op:·str,·value:·str)·->· | 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·with | 64 | ····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 modified | Offset 93, 21 lines modified | ||
| 93 | ····#·3·numb,·2·flags,·1·coord·pair | 93 | ····#·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:· | 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( | 102 | ········res.extend([op,·cast(list[float],·list(float(num)·for·num·in·seq.groups()))]) |
| 103 | ····return·res | 103 | ····return·res |
| 104 | def·normalise_svg_path(attr:·str)·->· | 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·format | 106 | ····Parses·raw·SVG·path·string·and·converts·it·into·a·standardized·list·format |
| 107 | ····where·each·path·command·is·paired·with·its·coordinate·parameters.·Automatically | 107 | ····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 modified | Offset 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:· | 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 | ············continue | 165 | ············continue |
| 166 | ········if·item·in·op_keys: | 166 | ········if·item·in·op_keys: |
| 167 | ············op·=·item | 167 | ············op·=·item |
| Offset 175, 17 lines modified | Offset 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·op | 176 | ············op·=·cast(str,·result[-2])··#·Remember·last·op |
| 177 | ····return·result | 177 | ····return·result |
| 178 | def·convert_quadratic_to_cubic_path( | 178 | def·convert_quadratic_to_cubic_path( |
| 179 | ····q0:· | 179 | ····q0:·tuple[float,·float],·q1:·tuple[float,·float],·q2:·tuple[float,·float] |
| 180 | )·->· | 180 | )·->·tuple[ |
| 181 | ···· | 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,·q2 | 184 | ····Converts·a·quadratic·Bezier·curve·defined·by·control·points·q0,·q1,·q2 |
| 185 | ····into·an·equivalent·cubic·Bezier·curve.·This·is·useful·for·SVG·processing | 185 | ····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 modified | Offset 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:· | 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·to | 223 | ····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 modified | Offset 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 | )·->· | 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. | |||
| Offset 1, 71 lines modified | Offset 1, 74 lines modified | ||
| 1 | #·coding:·utf-8 | ||
| 2 | """ | 1 | """ |
| 3 | ····webencodings | 2 | ····webencodings |
| 4 | ····~~~~~~~~~~~~ | 3 | ····~~~~~~~~~~~~ |
| 5 | ····This·is·a·Python·implementation·of·the·`WHATWG·Encoding·standard | 4 | ····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·Sapin | 6 | ····: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·codecs | 9 | import·codecs |
| 10 | from·.custom·import·replacement_codec_info,·user_codec_info | ||
| 12 | from·.labels·import·LABELS | 11 | 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 | 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 | ···· | 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-insensitive | 30 | ····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:` | 35 | ····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·=· | 38 | ········>>>·keyword·=·'Bac\\N{KELVIN·SIGN}ground' |
| 34 | ········>>>·assert·keyword.lower()·==· | 39 | ········>>>·assert·keyword.lower()·==·'background' |
| 35 | ········>>>·assert·ascii_lower(keyword)·!=·keyword.lower() | 40 | ········>>>·assert·ascii_lower(keyword)·!=·keyword.lower() |
| 36 | ········>>>·assert·ascii_lower(keyword)·==· | 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( | 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 | 47 | ····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 modified | Offset 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·None | 80 | ········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 | ············ | 84 | ············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]·=·encoding | 92 | ········CACHE[name]·=·encoding |
| 88 | ····return·encoding | 93 | ····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:` | 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_label | 101 | ········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: | 104 | ········raise·LookupError(f'Unknown·encoding·label:·{encoding_or_label!r}') |
| 101 | ····return·encoding | 105 | ····return·encoding |
| 102 | class·Encoding | 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::·name | 108 | ····..·attribute::·name |
| 106 | ········Canonical·name·of·the·encoding | 109 | ········Canonical·name·of·the·encoding |
| Max diff block lines reached; 6493/11193 bytes (58.01%) of diff not shown. | |||
| Offset 1, 1 lines modified | Offset 1, 1 lines modified | ||
| 1 | u | 1 | us-ascii |
| Offset 11, 16 lines modified | Offset 11, 19 lines modified | ||
| 11 | """ | 11 | """ |
| 12 | #·XXX·Do·not·edit! | 12 | #·XXX·Do·not·edit! |
| 13 | #·This·file·is·automatically·generated·by·mklabels.py | 13 | #·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 modified | Offset 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 modified | Offset 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 modified | Offset 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':·········' | 229 | ····'csiso2022kr':·········'replacement', |
| 230 | ····'hz-gb-2312':··········'replacement', | ||
| 231 | ····'iso-2022-cn':·········'replacement', | ||
| 232 | ····'iso-2022-cn-ext':·····'replacement', | ||
| 226 | ····'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 | } |
| Offset 1, 10 lines modified | Offset 1, 10 lines modified | ||
| 1 | Metadata-Version:·2.4 | 1 | Metadata-Version:·2.4 |
| 2 | Name:·charset-normalizer | 2 | Name:·charset-normalizer |
| 3 | Version:·3. | 3 | 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:·MIT | 7 | License:·MIT |
| 8 | Project-URL:·Changelog,·https://github.com/jawah/charset_normalizer/blob/master/CHANGELOG.md | 8 | 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_normalizer | 10 | Project-URL:·Code,·https://github.com/jawah/charset_normalizer |
| Offset 19, 18 lines modified | Offset 19, 21 lines modified | ||
| 19 | Classifier:·Programming·Language·::·Python·::·3.8 | 19 | Classifier:·Programming·Language·::·Python·::·3.8 |
| 20 | Classifier:·Programming·Language·::·Python·::·3.9 | 20 | Classifier:·Programming·Language·::·Python·::·3.9 |
| 21 | Classifier:·Programming·Language·::·Python·::·3.10 | 21 | Classifier:·Programming·Language·::·Python·::·3.10 |
| 22 | Classifier:·Programming·Language·::·Python·::·3.11 | 22 | Classifier:·Programming·Language·::·Python·::·3.11 |
| 23 | Classifier:·Programming·Language·::·Python·::·3.12 | 23 | Classifier:·Programming·Language·::·Python·::·3.12 |
| 24 | Classifier:·Programming·Language·::·Python·::·3.13 | 24 | Classifier:·Programming·Language·::·Python·::·3.13 |
| 25 | Classifier:·Programming·Language·::·Python·::·3.14 | 25 | Classifier:·Programming·Language·::·Python·::·3.14 |
| 26 | Classifier:·Programming·Language·::·Python·::·3.15 | ||
| 26 | Classifier:·Programming·Language·::·Python·::·3·::·Only | 27 | Classifier:·Programming·Language·::·Python·::·3·::·Only |
| 27 | Classifier:·Programming·Language·::·Python·::·Implementation·::·CPython | 28 | Classifier:·Programming·Language·::·Python·::·Implementation·::·CPython |
| 28 | Classifier:·Programming·Language·::·Python·::·Implementation·::·PyPy | 29 | Classifier:·Programming·Language·::·Python·::·Implementation·::·PyPy |
| 29 | Classifier:·Programming·Language·::·Python·::·Free·Threading·::·4·-·Resilient | 30 | Classifier:·Programming·Language·::·Python·::·Free·Threading·::·4·-·Resilient |
| 31 | Classifier:·Environment·::·WebAssembly | ||
| 32 | Classifier:·Environment·::·WebAssembly·::·Emscripten | ||
| 30 | Classifier:·Topic·::·Text·Processing·::·Linguistic | 33 | Classifier:·Topic·::·Text·Processing·::·Linguistic |
| 31 | Classifier:·Topic·::·Utilities | 34 | Classifier:·Topic·::·Utilities |
| 32 | Classifier:·Typing·::·Typed | 35 | Classifier:·Typing·::·Typed |
| 33 | Requires-Python:·>=3.7 | 36 | Requires-Python:·>=3.7 |
| 34 | Description-Content-Type:·text/markdown | 37 | Description-Content-Type:·text/markdown |
| 35 | License-File:·LICENSE | 38 | License-File:·LICENSE |
| 36 | Provides-Extra:·unicode-backport | 39 | Provides-Extra:·unicode-backport |
| Offset 72, 56 lines modified | Offset 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`········································|········ | 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 | |·` | 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· | 94 | [^1]:·They·are·clearly·using·specific·code·for·a·specific·encoding·even·if·covering·most·of·them. |
| 91 | [^2]:·Chardet·7 | 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 | ##·⚡·Performance | 96 | ##·⚡·Performance |
| 93 | This·package·offer· | 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 | |· | 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·4 | 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 | >· | 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 | ##·✨·Installation | 123 | ##·✨·Installation |
| 111 | Using·pip: | 124 | Using·pip: |
| 112 | ```sh | 125 | ```sh |
| 113 | pip·install·charset-normalizer·-U | 126 | pip·install·charset-normalizer·-U |
| Offset 296, 14 lines modified | Offset 310, 65 lines modified | ||
| 296 | [](https://www.bestpractices.dev/projects/7297) | 310 | [](https://www.bestpractices.dev/projects/7297) |
| 297 | #·Changelog | 311 | #·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. | |||
| Offset 1, 8 lines modified | Offset 1, 8 lines modified | ||
| 1 | Metadata-Version:·2.4·Name:·charset-normalizer·Version:·3. | 1 | Metadata-Version:·2.4·Name:·charset-normalizer·Version:·3.5.2·Summary:·The·Real |
| 2 | First·Universal·Charset·Detector.·Open,·modern·and·actively·maintained | 2 | 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 modified | Offset 12, 23 lines modified | ||
| 12 | Classifier:·Operating·System·::·OS·Independent·Classifier:·Programming·Language | 12 | 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· | 19 | 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 | 20 | 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·Detector | 29 | ···················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·Packages | 33 | ·······························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 modified | Offset 41, 154 lines modified | ||
| 40 | and·yes,·it·would·work·as-is.·This·project·offers·you·an·alternative·to | 41 | 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 | 48 | |·|·`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·spoken | 53 | _restrictive_·|·|·`Native·Python`·|·â ·|·â ·|·â·|·|·`Detect·spoken |
| 52 | language`·|·â
·|·â
·|·N/A·|·|·`UnicodeDecodeError·Safety`·|·â | 54 | language`·|·â ·|·â ·|·N/A·|·|·`UnicodeDecodeError·Safety`·|·â·|·â ·|·â·| |
| 53 | |·`Whl·Size | 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·if | 60 | [^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 | 61 | 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. | |||
| Offset 1, 10 lines modified | Offset 1, 10 lines modified | ||
| 1 | Metadata-Version:·2. | 1 | Metadata-Version:·2.5 |
| 2 | Name:·cssselect2 | 2 | Name:·cssselect2 |
| 3 | Version:·0. | 3 | Version:·0.10.1 |
| 4 | Summary:·CSS·selectors·for·Python·ElementTree | 4 | Summary:·CSS·selectors·for·Python·ElementTree |
| 5 | Keywords:·css,elementtree | 5 | 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.10 | 8 | Requires-Python:·>=3.10 |
| 9 | Description-Content-Type:·text/x-rst | 9 | Description-Content-Type:·text/x-rst |
| 10 | Classifier:·Development·Status·::·5·-·Production/Stable | 10 | Classifier:·Development·Status·::·5·-·Production/Stable |
| Offset 33, 14 lines modified | Offset 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/courtbouillon | 35 | 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/issues | 37 | Project-URL:·Issues,·https://github.com/Kozea/cssselect2/issues |
| 38 | Provides-Extra:·doc | 38 | Provides-Extra:·doc |
| 39 | Provides-Extra:·test | 39 | Provides-Extra:·test |
| 40 | Import-Name:·cssselect2 | ||
| 40 | cssselect2·is·a·straightforward·implementation·of·CSS4·Selectors·for·markup | 41 | cssselect2·is·a·straightforward·implementation·of·CSS4·Selectors·for·markup |
| 41 | documents·(HTML,·XML,·etc.)·that·can·be·read·by·ElementTree-like·parsers | 42 | 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·license | 44 | *·Free·software:·BSD·license |
| 44 | *·For·Python·3.10+,·tested·on·CPython·and·PyPy | 45 | *·For·Python·3.10+,·tested·on·CPython·and·PyPy |
| Offset 1, 10 lines modified | Offset 1, 10 lines modified | ||
| 1 | Metadata-Version:·2. | 1 | Metadata-Version:·2.5 |
| 2 | Name:·filelock | 2 | Name:·filelock |
| 3 | Version:· | 3 | 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.io | 5 | Project-URL:·Documentation,·https://py-filelock.readthedocs.io |
| 6 | Project-URL:·Homepage,·https://github.com/tox-dev/py-filelock | 6 | Project-URL:·Homepage,·https://github.com/tox-dev/py-filelock |
| 7 | Project-URL:·Source,·https://github.com/tox-dev/py-filelock | 7 | Project-URL:·Source,·https://github.com/tox-dev/py-filelock |
| 8 | Project-URL:·Tracker,·https://github.com/tox-dev/py-filelock/issues | 8 | 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:·MIT | 10 | License-Expression:·MIT |
| Offset 12, 24 lines modified | Offset 12, 23 lines modified | ||
| 12 | Keywords:·application,cache,directory,log,user | 12 | Keywords:·application,cache,directory,log,user |
| 13 | Classifier:·Development·Status·::·5·-·Production/Stable | 13 | Classifier:·Development·Status·::·5·-·Production/Stable |
| 14 | Classifier:·Intended·Audience·::·Developers | 14 | Classifier:·Intended·Audience·::·Developers |
| 15 | Classifier:·License·::·OSI·Approved·::·MIT·License | 15 | Classifier:·License·::·OSI·Approved·::·MIT·License |
| 16 | Classifier:·Operating·System·::·OS·Independent | 16 | Classifier:·Operating·System·::·OS·Independent |
| 17 | Classifier:·Programming·Language·::·Python | 17 | Classifier:·Programming·Language·::·Python |
| 18 | Classifier:·Programming·Language·::·Python·::·3·::·Only | 18 | Classifier:·Programming·Language·::·Python·::·3·::·Only |
| 19 | Classifier:·Programming·Language·::·Python·::·3.10 | ||
| 20 | Classifier:·Programming·Language·::·Python·::·3.11 | 19 | Classifier:·Programming·Language·::·Python·::·3.11 |
| 21 | Classifier:·Programming·Language·::·Python·::·3.12 | 20 | Classifier:·Programming·Language·::·Python·::·3.12 |
| 22 | Classifier:·Programming·Language·::·Python·::·3.13 | 21 | Classifier:·Programming·Language·::·Python·::·3.13 |
| 23 | Classifier:·Programming·Language·::·Python·::·3.14 | 22 | Classifier:·Programming·Language·::·Python·::·3.14 |
| 24 | Classifier:·Programming·Language·::·Python·::·3.15 | 23 | Classifier:·Programming·Language·::·Python·::·3.15 |
| 25 | Classifier:·Topic·::·Internet | 24 | Classifier:·Topic·::·Internet |
| 26 | Classifier:·Topic·::·Software·Development·::·Libraries | 25 | Classifier:·Topic·::·Software·Development·::·Libraries |
| 27 | Classifier:·Topic·::·System | 26 | Classifier:·Topic·::·System |
| 28 | Requires-Python:·>=3.1 | 27 | Requires-Python:·>=3.11 |
| 29 | Description-Content-Type:·text/markdown | 28 | Description-Content-Type:·text/markdown |
| 30 | #·filelock | 29 | #·filelock |
| 31 | [](https://pypi.org/project/filelock/) | 30 | [](https://pypi.org/project/filelock/) |
| 32 | [](https://pypi.org/project/filelock/) | 31 | [](https://pypi.org/project/filelock/) |
| 33 | [](https://py-filelock.readthedocs.io/en/latest/?badge=latest) | 32 | [](https://py-filelock.readthedocs.io/en/latest/?badge=latest) |
| Offset 1, 10 lines modified | Offset 1, 10 lines modified | ||
| 1 | Metadata-Version:·2.4 | 1 | Metadata-Version:·2.4 |
| 2 | Name:·reportlab | 2 | Name:·reportlab |
| 3 | Version:·5.0. | 3 | Version:·5.0.1 |
| 4 | Summary:·The·Reportlab·Toolkit | 4 | 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·community | 6 | Author:·Andy·Robinson,·Robin·Becker,·the·ReportLab·team·and·the·community |
| 7 | Author-email:·reportlab-users@lists2.reportlab.com | 7 | 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/Stable | 9 | Classifier:·Development·Status·::·5·-·Production/Stable |
| 10 | Classifier:·Intended·Audience·::·Developers | 10 | Classifier:·Intended·Audience·::·Developers |
| Offset 1, 35 lines modified | Offset 1, 34 lines modified | ||
| 1 | Metadata-Version:·2. | 1 | Metadata-Version:·2.5 |
| 2 | Name:·soupsieve | 2 | Name:·soupsieve |
| 3 | Version:· | 3 | 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/soupsieve | 5 | 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:·MIT | 7 | License-Expression:·MIT |
| 8 | License-File:·LICENSE.md | 8 | License-File:·LICENSE.md |
| 9 | Keywords:·CSS,HTML,XML,filter,query,selector,soup | 9 | Keywords:·CSS,HTML,XML,filter,query,selector,soup |
| 10 | Classifier:·Development·Status·::·5·-·Production/Stable | 10 | Classifier:·Development·Status·::·5·-·Production/Stable |
| 11 | Classifier:·Environment·::·Console | 11 | Classifier:·Environment·::·Console |
| 12 | Classifier:·Intended·Audience·::·Developers | 12 | Classifier:·Intended·Audience·::·Developers |
| 13 | Classifier:·License·::·OSI·Approved·::·MIT·License | 13 | Classifier:·License·::·OSI·Approved·::·MIT·License |
| 14 | Classifier:·Operating·System·::·OS·Independent | 14 | Classifier:·Operating·System·::·OS·Independent |
| 15 | Classifier:·Programming·Language·::·Python·::·3 | 15 | Classifier:·Programming·Language·::·Python·::·3 |
| 16 | Classifier:·Programming·Language·::·Python·::·3.10 | ||
| 17 | Classifier:·Programming·Language·::·Python·::·3.11 | 16 | Classifier:·Programming·Language·::·Python·::·3.11 |
| 18 | Classifier:·Programming·Language·::·Python·::·3.12 | 17 | Classifier:·Programming·Language·::·Python·::·3.12 |
| 19 | Classifier:·Programming·Language·::·Python·::·3.13 | 18 | Classifier:·Programming·Language·::·Python·::·3.13 |
| 20 | Classifier:·Programming·Language·::·Python·::·3.14 | 19 | Classifier:·Programming·Language·::·Python·::·3.14 |
| 20 | Classifier:·Programming·Language·::·Python·::·3.15 | ||
| 21 | Classifier:·Topic·::·Internet·::·WWW/HTTP·::·Dynamic·Content | 21 | Classifier:·Topic·::·Internet·::·WWW/HTTP·::·Dynamic·Content |
| 22 | Classifier:·Topic·::·Software·Development·::·Libraries·::·Python·Modules | 22 | Classifier:·Topic·::·Software·Development·::·Libraries·::·Python·Modules |
| 23 | Classifier:·Typing·::·Typed | 23 | Classifier:·Typing·::·Typed |
| 24 | Requires-Python:·>=3.1 | 24 | Requires-Python:·>=3.11.5 |
| 25 | Description-Content-Type:·text/markdown | 25 | 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·Sieve | 32 | #·Soup·Sieve |
| Offset 61, 51 lines modified | Offset 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 | ##·Installation | 61 | ##·Installation |
| 63 | You·must·have·Beautiful·Soup·already·installed: | 62 | You·must·have·Beautiful·Soup·already·installed: |
| 64 | ``` | 63 | ```console |
| 65 | pip·install·beautifulsoup4 | 64 | $·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·via | 66 | 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·soupsieve | 69 | $·pip·install·soupsieve |
| 71 | ``` | 70 | ``` |
| 72 | If·you·want·to·manually·install·it·from·source,·first·ensure·that·[`build`](https://pypi.org/project/build/)·is | 71 | 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·build | 74 | $·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·-w | 78 | $·python·-m·build·-w |
| 80 | pip·install·dist/soupsieve-<ver>-py3-none-any.whl | 79 | $·pip·install·dist/soupsieve-<ver>-py3-none-any.whl |
| 81 | ``` | 80 | ``` |
| 82 | ##·Documentation | 81 | ##·Documentation |
| 83 | Documentation·is·found·here:·https://facelessuser.github.io/soupsieve/. | 82 | Documentation·is·found·here:·https://facelessuser.github.io/soupsieve/. |
| 84 | ##·License | 83 | ##·License |
| 85 | MIT | 84 | 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=333333 | 86 | [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/soupsieve | 87 | [codecov-link]:·https://codecov.io/github/facelessuser/soupsieve |
| 91 | [pypi-image]:·https://img.shields.io/pypi/v/soupsieve.svg?logo=pypi&logoColor=aaaaaa&labelColor=333333 | 88 | [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=333333 | 89 | [pypi-down]:·https://img.shields.io/pypi/dm/soupsieve.svg?logo=pypi&logoColor=aaaaaa&labelColor=333333 |
| 93 | [pypi-link]:·https://pypi.python.org/pypi/soupsieve | 90 | [pypi-link]:·https://pypi.python.org/pypi/soupsieve |
| 94 | [python-image]:·https://img.shields.io/pypi/pyversions/soupsieve?logo=python&logoColor=aaaaaa&labelColor=333333 | 91 | [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=333333 | 92 | [license-image-mit]:·https://img.shields.io/badge/license-MIT-blue.svg?labelColor=333333 |
| Offset 1, 10 lines modified | Offset 1, 10 lines modified | ||
| 1 | Metadata-Version:·2. | 1 | Metadata-Version:·2.5 |
| 2 | Name:·svglib | 2 | Name:·svglib |
| 3 | Version:·2. | 3 | Version:·2.3.0 |
| 4 | Summary:·A·pure-Python·library·for·reading·and·converting·SVG | 4 | Summary:·A·pure-Python·library·for·reading·and·converting·SVG |
| 5 | Project-URL:·Homepage,·https://github.com/deeplook/svglib | 5 | Project-URL:·Homepage,·https://github.com/deeplook/svglib |
| 6 | Author:·Dinu·Gherman | 6 | Author:·Dinu·Gherman |
| 7 | License-Expression:·LGPL-3.0-or-later | 7 | License-Expression:·LGPL-3.0-or-later |
| 8 | License-File:·LICENSE.txt | 8 | License-File:·LICENSE.txt |
| 9 | Keywords:·PDF,SVG,conversion,graphics,reportlab | 9 | Keywords:·PDF,SVG,conversion,graphics,reportlab |
| 10 | Classifier:·Development·Status·::·5·-·Production/Stable | 10 | Classifier:·Development·Status·::·5·-·Production/Stable |
| Offset 19, 14 lines modified | Offset 19, 15 lines modified | ||
| 19 | Classifier:·Programming·Language·::·Python | 19 | Classifier:·Programming·Language·::·Python |
| 20 | Classifier:·Programming·Language·::·Python·::·3·::·Only | 20 | Classifier:·Programming·Language·::·Python·::·3·::·Only |
| 21 | Classifier:·Programming·Language·::·Python·::·3.9 | 21 | Classifier:·Programming·Language·::·Python·::·3.9 |
| 22 | Classifier:·Programming·Language·::·Python·::·3.10 | 22 | Classifier:·Programming·Language·::·Python·::·3.10 |
| 23 | Classifier:·Programming·Language·::·Python·::·3.11 | 23 | Classifier:·Programming·Language·::·Python·::·3.11 |
| 24 | Classifier:·Programming·Language·::·Python·::·3.12 | 24 | Classifier:·Programming·Language·::·Python·::·3.12 |
| 25 | Classifier:·Programming·Language·::·Python·::·3.13 | 25 | Classifier:·Programming·Language·::·Python·::·3.13 |
| 26 | Classifier:·Programming·Language·::·Python·::·3.14 | ||
| 26 | Classifier:·Topic·::·Documentation | 27 | Classifier:·Topic·::·Documentation |
| 27 | Classifier:·Topic·::·Multimedia·::·Graphics·::·Graphics·Conversion | 28 | Classifier:·Topic·::·Multimedia·::·Graphics·::·Graphics·Conversion |
| 28 | Classifier:·Topic·::·Printing | 29 | Classifier:·Topic·::·Printing |
| 29 | Classifier:·Topic·::·Software·Development·::·Libraries·::·Python·Modules | 30 | Classifier:·Topic·::·Software·Development·::·Libraries·::·Python·Modules |
| 30 | Classifier:·Topic·::·Text·Processing·::·Markup·::·XML | 31 | Classifier:·Topic·::·Text·Processing·::·Markup·::·XML |
| 31 | Classifier:·Topic·::·Utilities | 32 | Classifier:·Topic·::·Utilities |
| 32 | Requires-Python:·>=3.9 | 33 | Requires-Python:·>=3.9 |
| Offset 94, 15 lines modified | Offset 95, 17 lines modified | ||
| 94 | -·support·Python·3.9+·and·PyPy3 | 95 | -·support·Python·3.9+·and·PyPy3 |
| 95 | ##·Known·limitations | 96 | ##·Known·limitations |
| 96 | -·`@import`·rules·in·stylesheets·are·ignored.·CSS·is·supported,·but·the·range | 97 | -·`@import`·rules·in·stylesheets·are·ignored.·CSS·is·supported,·but·the·range |
| 97 | ··of·supported·attributes·is·still·limited | 98 | ··of·supported·attributes·is·still·limited |
| 98 | -·clipp | 99 | -·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 | ##·Examples | 103 | ##·Examples |
| 101 | You·can·use·`svglib`·as·a·Python·package·e.g.·like·in·the·following | 104 | You·can·use·`svglib`·as·a·Python·package·e.g.·like·in·the·following |
| 102 | interactive·Python·session: | 105 | interactive·Python·session: |
| Offset 37, 15 lines modified | Offset 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":·" | 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":·[ |