mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Compare commits
1005 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1208416b92 | ||
|
|
e5cea3ad37 | ||
|
|
8c11992e59 | ||
|
|
b864e5da1f | ||
|
|
77939d2ca5 | ||
|
|
9cf18a8bdc | ||
|
|
c25aa1add4 | ||
|
|
3900a086b8 | ||
|
|
64c66e00d6 | ||
|
|
4ba2892168 | ||
|
|
aee68d20bb | ||
|
|
d4be55c2ea | ||
|
|
e2f7d5b2f9 | ||
|
|
9417eec81e | ||
|
|
d056201e5b | ||
|
|
93d731cc4b | ||
|
|
d24013d582 | ||
|
|
31f0d9b282 | ||
|
|
f7d4413c62 | ||
|
|
3131d56298 | ||
|
|
9c2355117c | ||
|
|
94029386ae | ||
|
|
0fbe57f96b | ||
|
|
5f6059ef73 | ||
|
|
ba8d7b541f | ||
|
|
b1238ab4eb | ||
|
|
287f89aa04 | ||
|
|
d5a62848dd | ||
|
|
03f954408a | ||
|
|
d4d362a9ca | ||
|
|
aea4d509c9 | ||
|
|
bdb0c8f645 | ||
|
|
c28cb3941f | ||
|
|
d66f4d5315 | ||
|
|
b088787f7b | ||
|
|
6363940d6c | ||
|
|
a58ede99f2 | ||
|
|
7e66db0d43 | ||
|
|
179de9fb67 | ||
|
|
500b0024f0 | ||
|
|
4bec66e1c6 | ||
|
|
1cdc5d3294 | ||
|
|
3d2c51962b | ||
|
|
5c81649b19 | ||
|
|
d64d33c809 | ||
|
|
b875057ae2 | ||
|
|
2e5b0330c7 | ||
|
|
c7d3358582 | ||
|
|
1df0a44958 | ||
|
|
3c8fb93ab4 | ||
|
|
95ef76f7a0 | ||
|
|
9953597bb6 | ||
|
|
91e206faa1 | ||
|
|
06ed5cc8cf | ||
|
|
483dfcdd2c | ||
|
|
a4330c3558 | ||
|
|
a6a92128f0 | ||
|
|
436be2b96a | ||
|
|
89323dadc2 | ||
|
|
7e3183ef16 | ||
|
|
854d3e4d80 | ||
|
|
3150b4ded6 | ||
|
|
1be262db40 | ||
|
|
3d76e1e1db | ||
|
|
8af4c5fd7b | ||
|
|
8dbf7b27ef | ||
|
|
2b4f607cbc | ||
|
|
cbaed46fb4 | ||
|
|
9cab670bf8 | ||
|
|
6fb15535ed | ||
|
|
4721b7df92 | ||
|
|
06c6244599 | ||
|
|
3a2a1d1b74 | ||
|
|
531f4babff | ||
|
|
0f2ea6a1f3 | ||
|
|
7069a1de0a | ||
|
|
6f8f42b06a | ||
|
|
8db7edb6d9 | ||
|
|
de0d323ad3 | ||
|
|
01486830e3 | ||
|
|
7a3f965396 | ||
|
|
058f8c5500 | ||
|
|
0e24cf48c6 | ||
|
|
e864e26592 | ||
|
|
59df92d700 | ||
|
|
283a8046aa | ||
|
|
9ba6027599 | ||
|
|
8312831bc9 | ||
|
|
2786831d32 | ||
|
|
7366a41b1c | ||
|
|
2b43d4817c | ||
|
|
050f0bd0ad | ||
|
|
7c56313d2b | ||
|
|
ab3862d7f4 | ||
|
|
f4b54082cf | ||
|
|
ff7055749c | ||
|
|
a1d9c649f6 | ||
|
|
1aeaf4afef | ||
|
|
5d3e12fca4 | ||
|
|
3ae6ce5216 | ||
|
|
f5fc30ae63 | ||
|
|
7a6000d181 | ||
|
|
15fdf1ee5b | ||
|
|
4c2ab63185 | ||
|
|
0a10e6cbea | ||
|
|
935e35bb40 | ||
|
|
698134caab | ||
|
|
f12875027c | ||
|
|
833371918d | ||
|
|
a5f08d77a7 | ||
|
|
f3e4d34092 | ||
|
|
a43a8c546e | ||
|
|
b85e134477 | ||
|
|
4064c84cb4 | ||
|
|
dc569e9921 | ||
|
|
5337dedadf | ||
|
|
f1b261b4f8 | ||
|
|
a5ed4070bf | ||
|
|
fa30d33c9b | ||
|
|
3d9fb36cde | ||
|
|
6603c46b41 | ||
|
|
c7025f70d5 | ||
|
|
d03c7267d6 | ||
|
|
0af106c85c | ||
|
|
da15bb282e | ||
|
|
ff808ad313 | ||
|
|
0897385a30 | ||
|
|
bac1cdc55f | ||
|
|
91b9ed17c2 | ||
|
|
f2cfa5f0a7 | ||
|
|
306943a9f5 | ||
|
|
ff5076b12c | ||
|
|
cea23d2b07 | ||
|
|
1dd5e84c9a | ||
|
|
cfbdf7f924 | ||
|
|
2080cc2067 | ||
|
|
9cc8f2dfa9 | ||
|
|
2315ce956e | ||
|
|
e73603945d | ||
|
|
98eef0804e | ||
|
|
fa79055821 | ||
|
|
4a099ab6bc | ||
|
|
9f58921a6f | ||
|
|
9b9dd1100a | ||
|
|
2abf21b134 | ||
|
|
f4b9bdfb29 | ||
|
|
429d1d1cce | ||
|
|
9d44f93192 | ||
|
|
b8bca5a148 | ||
|
|
8c1d923f3e | ||
|
|
04749c13f4 | ||
|
|
e2ccb48463 | ||
|
|
02840593bc | ||
|
|
8503e0de90 | ||
|
|
23fee2737c | ||
|
|
0a94e1393a | ||
|
|
9287169201 | ||
|
|
8605fea678 | ||
|
|
d9b6585804 | ||
|
|
30b8d7bdad | ||
|
|
436624b7a3 | ||
|
|
268a39fc61 | ||
|
|
317f432a20 | ||
|
|
cbcdcf4ad5 | ||
|
|
ce13fc5f03 | ||
|
|
c16f813794 | ||
|
|
6e9e15b929 | ||
|
|
776bda60ca | ||
|
|
322aa6887a | ||
|
|
f256934f93 | ||
|
|
2658c5c539 | ||
|
|
4e0890a50d | ||
|
|
73e1eeb57e | ||
|
|
514014f4fc | ||
|
|
508cf6b61d | ||
|
|
8782bf8cb0 | ||
|
|
94bdb6b97a | ||
|
|
2c90b128c3 | ||
|
|
cf465bdd81 | ||
|
|
05442bc667 | ||
|
|
aad1d848a6 | ||
|
|
09a1ce9b2b | ||
|
|
d9c808ded8 | ||
|
|
ba6757ad11 | ||
|
|
e18dda3e08 | ||
|
|
1fa69ebcc9 | ||
|
|
f0db8329be | ||
|
|
6ce372cfb6 | ||
|
|
7fc30b715a | ||
|
|
07c07ad806 | ||
|
|
d7e7001afd | ||
|
|
df6831694b | ||
|
|
14aa9d7108 | ||
|
|
3794c178be | ||
|
|
560cd6ca6c | ||
|
|
6996141448 | ||
|
|
968f2ad7c9 | ||
|
|
c05f23d99d | ||
|
|
19224505e8 | ||
|
|
06b0484ea3 | ||
|
|
9e4c8ad7d7 | ||
|
|
e103adaa52 | ||
|
|
89e3587c15 | ||
|
|
446285f348 | ||
|
|
c03d3a58ec | ||
|
|
334c15e879 | ||
|
|
c3d9a51d15 | ||
|
|
fddbf0728a | ||
|
|
32aa9933be | ||
|
|
a354f7bba1 | ||
|
|
b7811af211 | ||
|
|
471ec26873 | ||
|
|
a4a6e8dabe | ||
|
|
4416b2a467 | ||
|
|
c69ff172e5 | ||
|
|
9c38e904dd | ||
|
|
fd4f6941bf | ||
|
|
9f28643ac7 | ||
|
|
9135d29346 | ||
|
|
96af524aad | ||
|
|
3a9a1c93dd | ||
|
|
b0618b9c9a | ||
|
|
c789490294 | ||
|
|
bf2fbfc52d | ||
|
|
3613edf321 | ||
|
|
b06c0f8ff9 | ||
|
|
05900fbabf | ||
|
|
51ae26128b | ||
|
|
1b66332f06 | ||
|
|
7b4b325e9d | ||
|
|
5c09cc37c9 | ||
|
|
e96e0e113a | ||
|
|
2d7ec43173 | ||
|
|
536da88df7 | ||
|
|
09b5838fda | ||
|
|
415fac82b2 | ||
|
|
eb30fb7330 | ||
|
|
be54e89ba6 | ||
|
|
5f17d281a6 | ||
|
|
d918f7e51b | ||
|
|
cb6cf107ba | ||
|
|
c9546c2419 | ||
|
|
2a1b2ed24d | ||
|
|
889df336d6 | ||
|
|
12d288ffcd | ||
|
|
4dd453f92c | ||
|
|
e42be00054 | ||
|
|
c3491ebdc3 | ||
|
|
f39f103dbe | ||
|
|
cf06c25904 | ||
|
|
dde92d1269 | ||
|
|
46455e854e | ||
|
|
473d391ea0 | ||
|
|
1bc71b8f9e | ||
|
|
4773ffba58 | ||
|
|
b5c5e807ea | ||
|
|
471dbace44 | ||
|
|
507e1039a4 | ||
|
|
a8d5070e98 | ||
|
|
9e5e76080d | ||
|
|
e40488b56e | ||
|
|
e5629321db | ||
|
|
4cb755d375 | ||
|
|
9eb59946ce | ||
|
|
a623616629 | ||
|
|
798b3bc158 | ||
|
|
18044abbb6 | ||
|
|
6e515b00ca | ||
|
|
96a949189d | ||
|
|
9bd4385002 | ||
|
|
f0a85acb63 | ||
|
|
7fc0525577 | ||
|
|
18150fa70f | ||
|
|
ffea61b540 | ||
|
|
d6350c672a | ||
|
|
6176e16275 | ||
|
|
47e621aaf3 | ||
|
|
5e84692e7e | ||
|
|
6ab541ea4e | ||
|
|
034f427638 | ||
|
|
143036aa0a | ||
|
|
ec001a067f | ||
|
|
41239caa97 | ||
|
|
30718a3be5 | ||
|
|
ca44da8bdf | ||
|
|
4d6ca07596 | ||
|
|
ba6a815711 | ||
|
|
9ac77140b6 | ||
|
|
0bcfdd2c07 | ||
|
|
b1f4606231 | ||
|
|
8ec024a8fd | ||
|
|
6c6290d20f | ||
|
|
707fbcf649 | ||
|
|
fea3cc2564 | ||
|
|
1251750403 | ||
|
|
40045ae02d | ||
|
|
ae28139206 | ||
|
|
c6b0e0cee3 | ||
|
|
31644f1542 | ||
|
|
aeba695431 | ||
|
|
e7165e8b6e | ||
|
|
392821700c | ||
|
|
133e98f7e1 | ||
|
|
52a0982948 | ||
|
|
ad0116ac0b | ||
|
|
05487c9f66 | ||
|
|
e121f8e81b | ||
|
|
94dc7bb279 | ||
|
|
93613ec5e1 | ||
|
|
5089cb045e | ||
|
|
fa26b6815d | ||
|
|
cde5527c9f | ||
|
|
0674aa7d8f | ||
|
|
c56da459bc | ||
|
|
77d9c8dcf0 | ||
|
|
cae29ab96e | ||
|
|
8bc32ebe5e | ||
|
|
f461d4099c | ||
|
|
32d16803a6 | ||
|
|
302149e02d | ||
|
|
f2b4ed2893 | ||
|
|
73b1d4d877 | ||
|
|
14afeb0e53 | ||
|
|
68ddbf82e0 | ||
|
|
c020c6bbf7 | ||
|
|
b7ab716ee5 | ||
|
|
b47eccbff0 | ||
|
|
f798d2df92 | ||
|
|
bf5aa56dc0 | ||
|
|
0609686803 | ||
|
|
2a41320963 | ||
|
|
f5d4c9fc1c | ||
|
|
23d6233d42 | ||
|
|
e169d97713 | ||
|
|
1862d1d827 | ||
|
|
07bad48dbc | ||
|
|
a05842d051 | ||
|
|
d8879486bd | ||
|
|
e4292702aa | ||
|
|
59f1e59ff1 | ||
|
|
fa3010a50e | ||
|
|
11d700d0a7 | ||
|
|
5c351c8d17 | ||
|
|
f14ac7146c | ||
|
|
69280ee64f | ||
|
|
f66ab39a40 | ||
|
|
0cea9346e1 | ||
|
|
1a7df66e10 | ||
|
|
7e6c33152e | ||
|
|
e48ca2892b | ||
|
|
5d6ce6c986 | ||
|
|
7b08953c18 | ||
|
|
3d1a74dda9 | ||
|
|
877ba28d85 | ||
|
|
f68a80879e | ||
|
|
7b0ab173dd | ||
|
|
4a5534f330 | ||
|
|
010640ccc8 | ||
|
|
f6c09da968 | ||
|
|
2c21ecd1df | ||
|
|
e9bc79d5ff | ||
|
|
44599e9e7e | ||
|
|
910fe62d92 | ||
|
|
5a1beaffb8 | ||
|
|
bdf5434d7b | ||
|
|
096a3dc645 | ||
|
|
11aefa3e42 | ||
|
|
f7eb51204a | ||
|
|
3fde8f3b27 | ||
|
|
1795740517 | ||
|
|
4783df5737 | ||
|
|
b00e63e37e | ||
|
|
322165f404 | ||
|
|
074e4b3144 | ||
|
|
bd51adebdf | ||
|
|
afffb13902 | ||
|
|
afe5e96aee | ||
|
|
95f3c0d69d | ||
|
|
185111d197 | ||
|
|
439b44ee93 | ||
|
|
d39ddac486 | ||
|
|
f3a8e98511 | ||
|
|
703ab1eee0 | ||
|
|
d3028e0227 | ||
|
|
fe87ca8117 | ||
|
|
fa39705dcb | ||
|
|
e53c9d1540 | ||
|
|
8d3ca534c4 | ||
|
|
6f8a652653 | ||
|
|
cfed9f3958 | ||
|
|
44da572893 | ||
|
|
57b0ca644e | ||
|
|
f750c0ca06 | ||
|
|
25ca331dc8 | ||
|
|
a209c1a7dc | ||
|
|
0873e451a8 | ||
|
|
0eea760443 | ||
|
|
62ae7339fe | ||
|
|
887ffd1116 | ||
|
|
d5975a4023 | ||
|
|
057d6aa497 | ||
|
|
395e7b390a | ||
|
|
c36e3612e7 | ||
|
|
8b6ef48046 | ||
|
|
31c33c87c5 | ||
|
|
8c9a33b737 | ||
|
|
286810d25b | ||
|
|
8c5a279ba2 | ||
|
|
c7081f90e8 | ||
|
|
6e921912d7 | ||
|
|
c132c66ac6 | ||
|
|
e3bf553dc3 | ||
|
|
7c3115ded6 | ||
|
|
db2fa98b52 | ||
|
|
42ee90b4d5 | ||
|
|
f5d2b869c0 | ||
|
|
919a2fbfda | ||
|
|
09c2dc2e85 | ||
|
|
a3c1082bb1 | ||
|
|
3a13a7bfda | ||
|
|
1a698fae33 | ||
|
|
0772f6fe16 | ||
|
|
f63e6f3e1b | ||
|
|
b636979127 | ||
|
|
55bb584360 | ||
|
|
5cce71db44 | ||
|
|
adb8d08995 | ||
|
|
6baddab4da | ||
|
|
5e51f2a6ed | ||
|
|
701efe8903 | ||
|
|
791111b060 | ||
|
|
999925744c | ||
|
|
7188e0486a | ||
|
|
993c892ad9 | ||
|
|
92b1a5bf3e | ||
|
|
4993925471 | ||
|
|
11e69eab36 | ||
|
|
e22ff3af36 | ||
|
|
7a5053dfb2 | ||
|
|
4d04e5522c | ||
|
|
ff1d4a1d4e | ||
|
|
7a6848595f | ||
|
|
d39b44c4d3 | ||
|
|
6a4ce0a620 | ||
|
|
494c7bda58 | ||
|
|
8000235591 | ||
|
|
64e1df5cdb | ||
|
|
3817246915 | ||
|
|
c5ce44eaaa | ||
|
|
75e11daa95 | ||
|
|
91b06fbe03 | ||
|
|
fb7393e4bb | ||
|
|
0a8c642e93 | ||
|
|
6b848f5038 | ||
|
|
eee6e78ec1 | ||
|
|
9c3ced06d5 | ||
|
|
6a45c3e25a | ||
|
|
d6acd2ee7d | ||
|
|
ee78527a9e | ||
|
|
b08f415f80 | ||
|
|
80afab57d3 | ||
|
|
12297982c8 | ||
|
|
7da7929edf | ||
|
|
aad90154e5 | ||
|
|
7b99df6c48 | ||
|
|
70fb78d031 | ||
|
|
d41e46be14 | ||
|
|
73364fa2db | ||
|
|
44f6446f6c | ||
|
|
dfb37d9a44 | ||
|
|
ab1de2942c | ||
|
|
2ff3ae86d0 | ||
|
|
906dfd3b6c | ||
|
|
a824e7b379 | ||
|
|
a2b358613b | ||
|
|
99b7a5b482 | ||
|
|
725dac204f | ||
|
|
ccc8f7ed37 | ||
|
|
8d38bf8ded | ||
|
|
cdfc67661e | ||
|
|
4fba939726 | ||
|
|
cf2b48fc0c | ||
|
|
962b3659c6 | ||
|
|
717242636a | ||
|
|
29055ab4a6 | ||
|
|
29073cf711 | ||
|
|
cf82d6f0a5 | ||
|
|
8fd984a767 | ||
|
|
1db415d897 | ||
|
|
914e14bb8d | ||
|
|
c8eff6ec07 | ||
|
|
107a64003d | ||
|
|
47d2e7b658 | ||
|
|
13b4fd9b9f | ||
|
|
e95eafe02a | ||
|
|
2cc83ed1fe | ||
|
|
b052d646ee | ||
|
|
174ef52df7 | ||
|
|
1fda3ba969 | ||
|
|
f314328294 | ||
|
|
0f24d66234 | ||
|
|
fd028253fe | ||
|
|
2e4ff723aa | ||
|
|
1218ddd5dc | ||
|
|
330eaf3ed6 | ||
|
|
2758a0ec53 | ||
|
|
1f63fc4fea | ||
|
|
de481bcd67 | ||
|
|
12c96d06e4 | ||
|
|
b572b91783 | ||
|
|
ad29fbdd55 | ||
|
|
f21ad9b879 | ||
|
|
8851a246de | ||
|
|
23cfdfffba | ||
|
|
f5f0d1a43b | ||
|
|
8bfbfe3e46 | ||
|
|
21615cb158 | ||
|
|
b6b6766000 | ||
|
|
f37ec60456 | ||
|
|
b35861005e | ||
|
|
123559478e | ||
|
|
bbd8fb2342 | ||
|
|
310a83427c | ||
|
|
0b6546aa8d | ||
|
|
21afc1933a | ||
|
|
e800af70bb | ||
|
|
40d36165a4 | ||
|
|
f10b76f087 | ||
|
|
2efc566b14 | ||
|
|
089c8b7b0a | ||
|
|
134d9f1e98 | ||
|
|
7e0863ef81 | ||
|
|
e96dd96864 | ||
|
|
8ff947e83a | ||
|
|
d5fd7ff339 | ||
|
|
8a223b8178 | ||
|
|
19193cd2a4 | ||
|
|
c15f670f2c | ||
|
|
f583f9a2d4 | ||
|
|
70734a1f28 | ||
|
|
b458797979 | ||
|
|
754b1df51d | ||
|
|
0da079c98c | ||
|
|
7be91fc92c | ||
|
|
415cdb1ef9 | ||
|
|
17c5361d43 | ||
|
|
6cf99b4415 | ||
|
|
7a5d4ecdc9 | ||
|
|
1a7792e06f | ||
|
|
95e863cb6d | ||
|
|
9b55505cdf | ||
|
|
b687960c5d | ||
|
|
10ccbc6a31 | ||
|
|
0e2e7e533a | ||
|
|
d71910cdc2 | ||
|
|
3cb7c61026 | ||
|
|
08c73444c4 | ||
|
|
e686b64ff3 | ||
|
|
7d1fae001b | ||
|
|
f190cdb3ec | ||
|
|
6275435567 | ||
|
|
5a90b14099 | ||
|
|
bca7c16435 | ||
|
|
925962505e | ||
|
|
e95529aca0 | ||
|
|
ed7bcf787c | ||
|
|
87728c4452 | ||
|
|
134f62a776 | ||
|
|
8fb53964e4 | ||
|
|
eb7daf1b74 | ||
|
|
ea665cb743 | ||
|
|
2287720201 | ||
|
|
91b57a3f28 | ||
|
|
97d69bd437 | ||
|
|
3c4ac0e5a2 | ||
|
|
9822749c92 | ||
|
|
d9fc95c2a1 | ||
|
|
788ccffb2b | ||
|
|
1fea829760 | ||
|
|
53b89b704c | ||
|
|
a949c35228 | ||
|
|
81fbcbc1b2 | ||
|
|
05317f1664 | ||
|
|
8a42a68a4f | ||
|
|
984db6798c | ||
|
|
ba9c354e1b | ||
|
|
f1dc0a6fcb | ||
|
|
13d715e2a5 | ||
|
|
1fceeab0fc | ||
|
|
51020cd635 | ||
|
|
4d05077ec3 | ||
|
|
5b6a4c4563 | ||
|
|
8e834cbdfc | ||
|
|
27233364bc | ||
|
|
685532d44a | ||
|
|
692c8036b7 | ||
|
|
f9715c442a | ||
|
|
e73a1c3298 | ||
|
|
129a6f187e | ||
|
|
7710ed00d3 | ||
|
|
fcc17254f6 | ||
|
|
6edd3705a6 | ||
|
|
58f988bf33 | ||
|
|
34a0615ac1 | ||
|
|
5a74f08c84 | ||
|
|
bdce56df30 | ||
|
|
f4a7b652c7 | ||
|
|
cb479bf199 | ||
|
|
b10421a9b4 | ||
|
|
ef77e45427 | ||
|
|
823b5288f9 | ||
|
|
c17951e3f6 | ||
|
|
f0a29de87d | ||
|
|
b60271a6cf | ||
|
|
f00e6b69f2 | ||
|
|
cc8515041b | ||
|
|
01512e27a0 | ||
|
|
301b79c688 | ||
|
|
98654634ca | ||
|
|
1812bd17a5 | ||
|
|
7b6486cd30 | ||
|
|
223fe14d85 | ||
|
|
5eb775462d | ||
|
|
ed60687f11 | ||
|
|
66d9514e12 | ||
|
|
37cc852bfc | ||
|
|
10eb20e44b | ||
|
|
7744e95aea | ||
|
|
3f871f0805 | ||
|
|
db7b945262 | ||
|
|
64aef5c13c | ||
|
|
3fe5a368ac | ||
|
|
f23a8480e7 | ||
|
|
5d6a48b568 | ||
|
|
df48df5ede | ||
|
|
51fcfe980f | ||
|
|
e983506e23 | ||
|
|
456bc80697 | ||
|
|
5be22a073b | ||
|
|
26a3ec9ae3 | ||
|
|
8d6d47a5c6 | ||
|
|
5adae77e39 | ||
|
|
79840126b9 | ||
|
|
05d0248b18 | ||
|
|
2a61e1cace | ||
|
|
abf850af91 | ||
|
|
0722db10df | ||
|
|
1fece09687 | ||
|
|
9f0db9a02a | ||
|
|
6f499013f6 | ||
|
|
29de419c87 | ||
|
|
9bde9c9fbb | ||
|
|
865c4984f6 | ||
|
|
987ad12181 | ||
|
|
003f3b4fe1 | ||
|
|
18f6a659f4 | ||
|
|
6e0de0d196 | ||
|
|
4d464cc9fb | ||
|
|
4030807b9b | ||
|
|
174fbe56b0 | ||
|
|
ab7971de42 | ||
|
|
65224213d0 | ||
|
|
992f5aaed7 | ||
|
|
298b169dc0 | ||
|
|
3fd46e8cbe | ||
|
|
9c10d4aa3f | ||
|
|
a7b8768e56 | ||
|
|
5d482abb67 | ||
|
|
1871a1632e | ||
|
|
4e19be7e43 | ||
|
|
ff973caa67 | ||
|
|
362be9f344 | ||
|
|
904e3a3492 | ||
|
|
404c398b59 | ||
|
|
1f92212497 | ||
|
|
d7f65cbbcd | ||
|
|
b4124d0d92 | ||
|
|
f3e9413b2d | ||
|
|
d09527b75e | ||
|
|
ad05321d94 | ||
|
|
822f6a9fa6 | ||
|
|
b846311173 | ||
|
|
cdf5634cf2 | ||
|
|
2d02933d35 | ||
|
|
11991772f8 | ||
|
|
ab9573f108 | ||
|
|
195673b01a | ||
|
|
c656cdd951 | ||
|
|
1bec1d5f26 | ||
|
|
7a12d1e322 | ||
|
|
25ddf1d1e9 | ||
|
|
6e4c2fe786 | ||
|
|
a7c9856851 | ||
|
|
78382209d3 | ||
|
|
c32bfa6eeb | ||
|
|
815083d1e8 | ||
|
|
b432bb0cf3 | ||
|
|
22bc2d24ab | ||
|
|
e5cf139b03 | ||
|
|
ec7b5861f9 | ||
|
|
58ac82b0a7 | ||
|
|
6d1f2986fe | ||
|
|
166959db41 | ||
|
|
367a948ff0 | ||
|
|
6d996834f3 | ||
|
|
e731e658ba | ||
|
|
f62e8f594d | ||
|
|
880ab910f7 | ||
|
|
2da4b70e3a | ||
|
|
f58014e2b3 | ||
|
|
dbfa61a156 | ||
|
|
8294d4ae8e | ||
|
|
8daffa76dd | ||
|
|
d55f554d7b | ||
|
|
a0472e11a9 | ||
|
|
c8d34fbe8c | ||
|
|
6ccb9814f8 | ||
|
|
733813700e | ||
|
|
af1d46f184 | ||
|
|
5f7fffbe81 | ||
|
|
71e11950d9 | ||
|
|
a1b74b0758 | ||
|
|
f2515405b5 | ||
|
|
3dc15623d5 | ||
|
|
ffe1b6e03a | ||
|
|
7265921719 | ||
|
|
58e24cea4b | ||
|
|
aa8336ee94 | ||
|
|
733ff9a05b | ||
|
|
1204996378 | ||
|
|
c0f5266bc4 | ||
|
|
1ca57407d3 | ||
|
|
e082d8cc75 | ||
|
|
94237df7b5 | ||
|
|
9377bef603 | ||
|
|
6ee827bd8a | ||
|
|
351d464448 | ||
|
|
fcacdb2791 | ||
|
|
e25b89d49a | ||
|
|
6385b82c2b | ||
|
|
622b62cff1 | ||
|
|
e206505061 | ||
|
|
4955f05fa3 | ||
|
|
258d1c0521 | ||
|
|
734b872e41 | ||
|
|
8405693325 | ||
|
|
910574361c | ||
|
|
0a8fa3a8ba | ||
|
|
0094064f4a | ||
|
|
7e37f8e3ed | ||
|
|
945a53353f | ||
|
|
e3111729c6 | ||
|
|
d41c786554 | ||
|
|
c40e26ada9 | ||
|
|
9a8364566c | ||
|
|
75aefb89fd | ||
|
|
a3e60af35e | ||
|
|
bc87fadc03 | ||
|
|
76e295f606 | ||
|
|
ad7544ce90 | ||
|
|
01a5355713 | ||
|
|
abcb93d0bd | ||
|
|
e45b5b35e3 | ||
|
|
a6e44a349a | ||
|
|
fe22f1e46a | ||
|
|
89bb079e50 | ||
|
|
f2e32857cb | ||
|
|
7492b46c43 | ||
|
|
ad20a404a9 | ||
|
|
496006d629 | ||
|
|
f2f8ecac73 | ||
|
|
204643b8da | ||
|
|
4f206c5f1e | ||
|
|
1e09c63282 | ||
|
|
c88248acb1 | ||
|
|
547d752df5 | ||
|
|
8b40c2e372 | ||
|
|
f51764f8d0 | ||
|
|
64f95fec69 | ||
|
|
8ca35fdf4f | ||
|
|
d87921c12a | ||
|
|
ae3de43a62 | ||
|
|
fbb5e78176 | ||
|
|
10de265b4f | ||
|
|
4a357ee6e9 | ||
|
|
40b96bfffd | ||
|
|
f53c68695d | ||
|
|
cfc2e3e228 | ||
|
|
25398fe622 | ||
|
|
a7c3740dee | ||
|
|
7de056437f | ||
|
|
cfa9de4047 | ||
|
|
c48fe567f7 | ||
|
|
c4b6789666 | ||
|
|
6404c4bca8 | ||
|
|
9423712696 | ||
|
|
5018b1a426 | ||
|
|
1336ca5d9d | ||
|
|
5e3046d86a | ||
|
|
e45536ae93 | ||
|
|
48254acb4e | ||
|
|
20b408ff3e | ||
|
|
4a579b5752 | ||
|
|
edf5995a1e | ||
|
|
6b2efdc9c3 | ||
|
|
17f5aed6dd | ||
|
|
fb44ded002 | ||
|
|
fea711cebb | ||
|
|
57efe6f75d | ||
|
|
6d71f75817 | ||
|
|
d570b1731e | ||
|
|
8fc263f62f | ||
|
|
3886f889ab | ||
|
|
f96942bdc0 | ||
|
|
f628a3fd7e | ||
|
|
f078f79c90 | ||
|
|
af45d22fb7 | ||
|
|
c3a7d8c433 | ||
|
|
6c7d81c325 | ||
|
|
a6f8c53924 | ||
|
|
6d5bbd913c | ||
|
|
4e957d3484 | ||
|
|
454ec3e74c | ||
|
|
ddf497623a | ||
|
|
746cb0493f | ||
|
|
2e27587f15 | ||
|
|
84c27f3694 | ||
|
|
42c0752370 | ||
|
|
3615b1620e | ||
|
|
e42553867f | ||
|
|
955347e426 | ||
|
|
468f1aa312 | ||
|
|
afb64c873a | ||
|
|
8f17468f51 | ||
|
|
78b58122c1 | ||
|
|
97ac351c5e | ||
|
|
c7f442425d | ||
|
|
df0963446f | ||
|
|
ef873b4b60 | ||
|
|
6a267debf5 | ||
|
|
334bb30f9e | ||
|
|
da9b2ee6b9 | ||
|
|
3ebf23e39b | ||
|
|
b5f54f1624 | ||
|
|
33da5bf81f | ||
|
|
43e3fd9c2c | ||
|
|
0201a5aadb | ||
|
|
fa38e9fa47 | ||
|
|
382df8e714 | ||
|
|
c5db729191 | ||
|
|
e0a294849a | ||
|
|
fcfe8e1ac8 | ||
|
|
4f1085beb3 | ||
|
|
e325a0003b | ||
|
|
e967e5ed11 | ||
|
|
d4aa062441 | ||
|
|
e5735cde67 | ||
|
|
75f3f3c8c4 | ||
|
|
3b8d670c81 | ||
|
|
8b7158f169 | ||
|
|
82c1a3a9ea | ||
|
|
53d0f41ba5 | ||
|
|
a5091c56cb | ||
|
|
daca1f38cf | ||
|
|
5df8d29fe4 | ||
|
|
8c38a8381c | ||
|
|
d22446d1dd | ||
|
|
c037e17220 | ||
|
|
506e17ace2 | ||
|
|
e88f09842d | ||
|
|
e79b1398b0 | ||
|
|
371b5e2a6e | ||
|
|
a4629db520 | ||
|
|
aaa364da54 | ||
|
|
a0c34dab54 | ||
|
|
1d815464f6 | ||
|
|
461f7491e8 | ||
|
|
abe8cfdf1c | ||
|
|
d9e3f9ca68 | ||
|
|
e08252cad7 | ||
|
|
9206ad52b8 | ||
|
|
57fd8c97b4 | ||
|
|
f9f665be62 | ||
|
|
3f1fb9d29d | ||
|
|
8afe853b76 | ||
|
|
5ec62358b3 | ||
|
|
dcda3e43b9 | ||
|
|
81fc6f16cf | ||
|
|
07f4218bf4 | ||
|
|
529d223ee1 | ||
|
|
3c4f04f3aa | ||
|
|
1fd557d549 | ||
|
|
9cac89347e | ||
|
|
020372dde0 | ||
|
|
bf49952275 | ||
|
|
491bd0e74f | ||
|
|
5c43cab499 | ||
|
|
317802a26e | ||
|
|
4bd090887e | ||
|
|
2fc0edf85b | ||
|
|
4192e5de2d | ||
|
|
443835096b | ||
|
|
d3855a9158 | ||
|
|
1d1ff8db7a | ||
|
|
937b0d3419 | ||
|
|
96bfe406ee | ||
|
|
271bfcbac7 | ||
|
|
5e40168829 | ||
|
|
bc9e4abee5 | ||
|
|
8d28a077fc | ||
|
|
61b48f1089 | ||
|
|
d4207e2936 | ||
|
|
65a62b8d32 | ||
|
|
cf54a780cf | ||
|
|
6d3cbf192e | ||
|
|
d94d0ac720 | ||
|
|
3942a08e0c | ||
|
|
3092c17080 | ||
|
|
b8a88719a7 | ||
|
|
e22d91b8c4 | ||
|
|
5adc09150d | ||
|
|
f3a0127715 | ||
|
|
b8d95537e0 | ||
|
|
398c44e334 | ||
|
|
74284c3271 | ||
|
|
1e9759679f | ||
|
|
e4096fb6f2 | ||
|
|
a3c372f602 | ||
|
|
42a22c280d | ||
|
|
adc23253e4 | ||
|
|
5025113da0 | ||
|
|
5fb03b6891 | ||
|
|
0fcac14fd7 | ||
|
|
7edf3c86c3 | ||
|
|
ecac89521b | ||
|
|
51ba929fc6 | ||
|
|
b6e4471458 | ||
|
|
763eaed2af | ||
|
|
e1ab8a9b42 | ||
|
|
daa9f116d0 | ||
|
|
c0ab8e8256 | ||
|
|
6d927ef83d | ||
|
|
78e815c861 | ||
|
|
8284a7cb89 | ||
|
|
03f0e717a7 | ||
|
|
778b8fdb2b | ||
|
|
d0bf163641 | ||
|
|
685a7e8ac5 | ||
|
|
a866d881e5 | ||
|
|
0527c4eae6 | ||
|
|
bdd3beb257 | ||
|
|
3b4b134328 | ||
|
|
4f38cb68e4 | ||
|
|
3d52769a47 | ||
|
|
8cb426120b | ||
|
|
9e8e5a1e81 | ||
|
|
88e3c83138 | ||
|
|
62aa942bf5 | ||
|
|
fc0b08042d | ||
|
|
225efcaf02 | ||
|
|
115357ddd1 | ||
|
|
a3507e7f58 | ||
|
|
189a490e27 | ||
|
|
52afc1ace5 | ||
|
|
f0c427b2d2 | ||
|
|
ff90fe52ee | ||
|
|
02ee5bcb6a | ||
|
|
16c1e214d6 | ||
|
|
019be59079 | ||
|
|
84caa50a08 | ||
|
|
59b191c789 | ||
|
|
6e7be1ec8d | ||
|
|
f4363c8a86 | ||
|
|
211bdb0bb7 | ||
|
|
c3709e8b04 | ||
|
|
c79b1fa87a | ||
|
|
964cc1b206 | ||
|
|
b31b08a30e | ||
|
|
15228f4463 | ||
|
|
e4102aae8d | ||
|
|
ac4fc783ae | ||
|
|
09ff71105a | ||
|
|
290736ae06 | ||
|
|
ea9db0ebbe | ||
|
|
82892f3e0e | ||
|
|
1640b6a7f3 | ||
|
|
fdd3beaf58 | ||
|
|
ae770996f6 | ||
|
|
cdb1323515 | ||
|
|
49b682edca | ||
|
|
e1f41e83d1 | ||
|
|
acbc517b55 | ||
|
|
253b62f8b0 | ||
|
|
cb97a80350 | ||
|
|
84897d4834 | ||
|
|
a9696d8501 | ||
|
|
8828fd17a0 | ||
|
|
aa3d24ea2a | ||
|
|
68d413e923 | ||
|
|
ee5a1c9002 | ||
|
|
2861c874ed | ||
|
|
91a897dd74 | ||
|
|
e64faa781c | ||
|
|
9bbe745a33 | ||
|
|
658d5a8b7e |
311
.cspell.json
311
.cspell.json
@@ -26,109 +26,260 @@
|
|||||||
"words": [
|
"words": [
|
||||||
// Rust
|
// Rust
|
||||||
"ahash",
|
"ahash",
|
||||||
"bitflags",
|
"bidi",
|
||||||
|
"biguint",
|
||||||
"bindgen",
|
"bindgen",
|
||||||
"cstring",
|
"bitflags",
|
||||||
|
"bstr",
|
||||||
|
"byteorder",
|
||||||
"chrono",
|
"chrono",
|
||||||
"peekable",
|
"consts",
|
||||||
|
"cstring",
|
||||||
|
"flate2",
|
||||||
|
"fract",
|
||||||
|
"hasher",
|
||||||
|
"idents",
|
||||||
|
"indexmap",
|
||||||
|
"insta",
|
||||||
|
"keccak",
|
||||||
"lalrpop",
|
"lalrpop",
|
||||||
"memmap",
|
"libc",
|
||||||
|
"libz",
|
||||||
|
"longlong",
|
||||||
"Manually",
|
"Manually",
|
||||||
|
"maplit",
|
||||||
|
"memmap",
|
||||||
|
"metas",
|
||||||
|
"modpow",
|
||||||
|
"nanos",
|
||||||
|
"peekable",
|
||||||
|
"powc",
|
||||||
|
"powf",
|
||||||
|
"prepended",
|
||||||
|
"punct",
|
||||||
|
"replacen",
|
||||||
|
"rsplitn",
|
||||||
"rustc",
|
"rustc",
|
||||||
"unistd",
|
"rustfmt",
|
||||||
|
"seekfrom",
|
||||||
|
"splitn",
|
||||||
|
"subsec",
|
||||||
|
"timsort",
|
||||||
|
"trai",
|
||||||
|
"ulonglong",
|
||||||
"unic",
|
"unic",
|
||||||
|
"unistd",
|
||||||
|
"winapi",
|
||||||
|
"winsock",
|
||||||
// Python
|
// Python
|
||||||
"cformat",
|
|
||||||
"cpython",
|
|
||||||
"fspath",
|
|
||||||
"kwarg",
|
|
||||||
"kwargs",
|
|
||||||
"vararg",
|
|
||||||
"varargs",
|
|
||||||
"metaclass",
|
|
||||||
"metaclasses",
|
|
||||||
"fstring",
|
|
||||||
"fstrings",
|
|
||||||
"docstring",
|
|
||||||
"docstrings",
|
|
||||||
"fileencoding",
|
|
||||||
"linearization",
|
|
||||||
"linearize",
|
|
||||||
"PYTHONDEBUG",
|
|
||||||
"PYTHONINSPECT",
|
|
||||||
"PYTHONPATH",
|
|
||||||
"PYTHONHOME",
|
|
||||||
"PYTHONPATH",
|
|
||||||
"PYTHONVERBOSE",
|
|
||||||
"PYTHONOPTIMIZE",
|
|
||||||
"PYTHONWARNINGS",
|
|
||||||
"basicsize",
|
|
||||||
"itemsize",
|
|
||||||
"getattro",
|
|
||||||
"setattro",
|
|
||||||
"iternext",
|
|
||||||
"maxsplit",
|
|
||||||
"fdel",
|
|
||||||
"subclasscheck",
|
|
||||||
"qualname",
|
|
||||||
"eventmask",
|
|
||||||
"instanceof",
|
|
||||||
"abstractmethods",
|
"abstractmethods",
|
||||||
"aiter",
|
"aiter",
|
||||||
"anext",
|
"anext",
|
||||||
"rdiv",
|
"arrayiterator",
|
||||||
"idiv",
|
"arraytype",
|
||||||
"ndim",
|
"asend",
|
||||||
"varnames",
|
"athrow",
|
||||||
"getweakrefs",
|
"basicsize",
|
||||||
"getweakrefcount",
|
"cformat",
|
||||||
"stacklevel",
|
"classcell",
|
||||||
"MemoryView",
|
"closesocket",
|
||||||
"warningregistry",
|
"codepoint",
|
||||||
|
"codepoints",
|
||||||
|
"cpython",
|
||||||
|
"decompressor",
|
||||||
"defaultaction",
|
"defaultaction",
|
||||||
"unraisablehook",
|
|
||||||
"descr",
|
"descr",
|
||||||
"xopts",
|
"dictcomp",
|
||||||
|
"dictitems",
|
||||||
|
"dictkeys",
|
||||||
|
"dictview",
|
||||||
|
"docstring",
|
||||||
|
"docstrings",
|
||||||
|
"dunder",
|
||||||
|
"eventmask",
|
||||||
|
"fdel",
|
||||||
|
"fget",
|
||||||
|
"fileencoding",
|
||||||
|
"fillchar",
|
||||||
|
"finallyhandler",
|
||||||
|
"frombytes",
|
||||||
|
"fromhex",
|
||||||
|
"fromunicode",
|
||||||
|
"fset",
|
||||||
|
"fspath",
|
||||||
|
"fstring",
|
||||||
|
"fstrings",
|
||||||
|
"genexpr",
|
||||||
|
"getattro",
|
||||||
|
"getformat",
|
||||||
|
"getnewargs",
|
||||||
|
"getweakrefcount",
|
||||||
|
"getweakrefs",
|
||||||
|
"hostnames",
|
||||||
|
"idiv",
|
||||||
|
"impls",
|
||||||
|
"infj",
|
||||||
|
"instancecheck",
|
||||||
|
"instanceof",
|
||||||
|
"isabstractmethod",
|
||||||
|
"itemiterator",
|
||||||
|
"itemsize",
|
||||||
|
"iternext",
|
||||||
|
"keyiterator",
|
||||||
|
"kwarg",
|
||||||
|
"kwargs",
|
||||||
|
"linearization",
|
||||||
|
"linearize",
|
||||||
|
"listcomp",
|
||||||
|
"mappingproxy",
|
||||||
|
"maxsplit",
|
||||||
|
"memoryview",
|
||||||
|
"memoryviewiterator",
|
||||||
|
"metaclass",
|
||||||
|
"metaclasses",
|
||||||
|
"metatype",
|
||||||
|
"mro",
|
||||||
|
"mros",
|
||||||
|
"nanj",
|
||||||
|
"ndigits",
|
||||||
|
"ndim",
|
||||||
|
"nonbytes",
|
||||||
|
"origname",
|
||||||
|
"posixsubprocess",
|
||||||
|
"pyexpat",
|
||||||
|
"PYTHONDEBUG",
|
||||||
|
"PYTHONHOME",
|
||||||
|
"PYTHONINSPECT",
|
||||||
|
"PYTHONOPTIMIZE",
|
||||||
|
"PYTHONPATH",
|
||||||
|
"PYTHONPATH",
|
||||||
|
"PYTHONVERBOSE",
|
||||||
|
"PYTHONWARNINGS",
|
||||||
|
"qualname",
|
||||||
|
"radd",
|
||||||
|
"rdiv",
|
||||||
|
"rdivmod",
|
||||||
|
"reconstructor",
|
||||||
|
"reversevalueiterator",
|
||||||
|
"rfloordiv",
|
||||||
|
"rlshift",
|
||||||
|
"rmod",
|
||||||
|
"rpow",
|
||||||
|
"rrshift",
|
||||||
|
"rsub",
|
||||||
|
"rtruediv",
|
||||||
|
"scproxy",
|
||||||
|
"setattro",
|
||||||
|
"setcomp",
|
||||||
|
"stacklevel",
|
||||||
|
"subclasscheck",
|
||||||
|
"subclasshook",
|
||||||
|
"unionable",
|
||||||
|
"unraisablehook",
|
||||||
|
"valueiterator",
|
||||||
|
"vararg",
|
||||||
|
"varargs",
|
||||||
|
"varnames",
|
||||||
|
"warningregistry",
|
||||||
"warnopts",
|
"warnopts",
|
||||||
"weakproxy",
|
"weakproxy",
|
||||||
"mappingproxy",
|
"xopts",
|
||||||
// RustPython
|
// RustPython
|
||||||
"RustPython",
|
"baseclass",
|
||||||
|
"Bytecode",
|
||||||
|
"cfgs",
|
||||||
|
"codegen",
|
||||||
|
"dedentations",
|
||||||
|
"dedents",
|
||||||
|
"deduped",
|
||||||
|
"downcasted",
|
||||||
|
"dumpable",
|
||||||
|
"GetSet",
|
||||||
|
"internable",
|
||||||
|
"makeunicodedata",
|
||||||
|
"miri",
|
||||||
|
"notrace",
|
||||||
|
"pyarg",
|
||||||
"pyarg",
|
"pyarg",
|
||||||
"pyargs",
|
"pyargs",
|
||||||
"pygetset",
|
|
||||||
"pyobj",
|
|
||||||
"pystr",
|
|
||||||
"pyc",
|
|
||||||
"pyref",
|
|
||||||
"pyslot",
|
|
||||||
"PyFunction",
|
|
||||||
"PyMethod",
|
|
||||||
"PyClassMethod",
|
|
||||||
"PyStaticMethod",
|
|
||||||
"PyProperty",
|
|
||||||
"PyClass",
|
|
||||||
"pyimpl",
|
|
||||||
"pyarg",
|
|
||||||
"PyModule",
|
|
||||||
"PyAttr",
|
"PyAttr",
|
||||||
"PyResult",
|
"pyc",
|
||||||
"PyObject",
|
"PyClass",
|
||||||
|
"PyClassMethod",
|
||||||
"PyException",
|
"PyException",
|
||||||
"GetSet",
|
"PyFunction",
|
||||||
"zelf",
|
"pygetset",
|
||||||
"wasi",
|
"pyimpl",
|
||||||
"Bytecode",
|
"pymember",
|
||||||
|
"PyMethod",
|
||||||
|
"PyModule",
|
||||||
|
"pyname",
|
||||||
|
"pyobj",
|
||||||
|
"PyObject",
|
||||||
|
"pypayload",
|
||||||
|
"PyProperty",
|
||||||
|
"pyref",
|
||||||
|
"PyResult",
|
||||||
|
"pyslot",
|
||||||
|
"PyStaticMethod",
|
||||||
|
"pystr",
|
||||||
|
"pystruct",
|
||||||
|
"pystructseq",
|
||||||
|
"pytrace",
|
||||||
|
"reducelib",
|
||||||
"richcompare",
|
"richcompare",
|
||||||
"makeunicodedata",
|
"RustPython",
|
||||||
"unhashable",
|
"struc",
|
||||||
"unraisable",
|
"tracebacks",
|
||||||
"typealiases",
|
"typealiases",
|
||||||
"Unconstructible",
|
"Unconstructible",
|
||||||
"posonlyargs",
|
"unhashable",
|
||||||
"kwonlyargs",
|
|
||||||
"uninit",
|
"uninit",
|
||||||
"miri"
|
"unraisable",
|
||||||
|
"wasi",
|
||||||
|
"zelf",
|
||||||
|
// cpython
|
||||||
|
"argtypes",
|
||||||
|
"asdl",
|
||||||
|
"asname",
|
||||||
|
"augassign",
|
||||||
|
"badsyntax",
|
||||||
|
"basetype",
|
||||||
|
"boolop",
|
||||||
|
"bxor",
|
||||||
|
"cellarg",
|
||||||
|
"cellvar",
|
||||||
|
"cellvars",
|
||||||
|
"cmpop",
|
||||||
|
"dictoffset",
|
||||||
|
"elts",
|
||||||
|
"excepthandler",
|
||||||
|
"finalbody",
|
||||||
|
"freevar",
|
||||||
|
"freevars",
|
||||||
|
"fromlist",
|
||||||
|
"heaptype",
|
||||||
|
"IMMUTABLETYPE",
|
||||||
|
"kwonlyarg",
|
||||||
|
"kwonlyargs",
|
||||||
|
"linearise",
|
||||||
|
"maxdepth",
|
||||||
|
"mult",
|
||||||
|
"nkwargs",
|
||||||
|
"orelse",
|
||||||
|
"patma",
|
||||||
|
"posonlyarg",
|
||||||
|
"posonlyargs",
|
||||||
|
"prec",
|
||||||
|
"stackdepth",
|
||||||
|
"unaryop",
|
||||||
|
"unparse",
|
||||||
|
"unparser",
|
||||||
|
"VARKEYWORDS",
|
||||||
|
"varkwarg",
|
||||||
|
"wbits",
|
||||||
|
"withitem",
|
||||||
|
"withs"
|
||||||
],
|
],
|
||||||
// flagWords - list of words to be always considered incorrect
|
// flagWords - list of words to be always considered incorrect
|
||||||
"flagWords": [
|
"flagWords": [
|
||||||
|
|||||||
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1,8 +1,6 @@
|
|||||||
Lib/** linguist-vendored
|
Lib/** linguist-vendored
|
||||||
Cargo.lock linguist-generated -merge
|
Cargo.lock linguist-generated -merge
|
||||||
*.snap linguist-generated -merge
|
*.snap linguist-generated -merge
|
||||||
ast/src/ast_gen.rs linguist-generated -merge
|
|
||||||
vm/src/stdlib/ast/gen.rs linguist-generated -merge
|
vm/src/stdlib/ast/gen.rs linguist-generated -merge
|
||||||
compiler/parser/python.lalrpop text eol=LF
|
|
||||||
Lib/*.py text working-tree-encoding=UTF-8 eol=LF
|
Lib/*.py text working-tree-encoding=UTF-8 eol=LF
|
||||||
**/*.rs text working-tree-encoding=UTF-8 eol=LF
|
**/*.rs text working-tree-encoding=UTF-8 eol=LF
|
||||||
|
|||||||
16
.github/ISSUE_TEMPLATE/empty.md
vendored
Normal file
16
.github/ISSUE_TEMPLATE/empty.md
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
name: Generic issue template
|
||||||
|
about: which is not covered by other templates
|
||||||
|
title: ''
|
||||||
|
labels:
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
<!-- Short description of the issue. -->
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
<!-- Whatever you want to share -->
|
||||||
16
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
16
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Request a feature to use RustPython (as a Rust library)
|
||||||
|
title: ''
|
||||||
|
labels: C-enhancement
|
||||||
|
assignees: 'youknowone'
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
<!-- Short description of the request. Please use incompatibility form to report missing features as Python interpreter -->
|
||||||
|
|
||||||
|
## Expected use case
|
||||||
|
|
||||||
|
<!-- By sharing detailed use case, we can understand the requirements better! If it will be used by open source projects, please also share the project URL. -->
|
||||||
24
.github/ISSUE_TEMPLATE/report-bug.md
vendored
Normal file
24
.github/ISSUE_TEMPLATE/report-bug.md
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
name: Report bugs
|
||||||
|
about: Report a bug not related to CPython compatibility
|
||||||
|
title: ''
|
||||||
|
labels: C-bug
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
<!-- Short description of the bug -->
|
||||||
|
|
||||||
|
## Expected
|
||||||
|
|
||||||
|
<!-- What's the expected result? Using ``` ``` block is preferred for text. -->
|
||||||
|
|
||||||
|
## Actual
|
||||||
|
|
||||||
|
<!-- What's the actual result? Using ``` ``` block is preferred for text. -->
|
||||||
|
|
||||||
|
## Python Documentation
|
||||||
|
|
||||||
|
<!-- If applicable. -->
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
name: Report incompatibility
|
name: Report incompatibility
|
||||||
about: Report an incompatibility between RustPython and CPython
|
about: Report an incompatibility between RustPython and CPython
|
||||||
title: ''
|
title: ''
|
||||||
labels: feat
|
labels: C-compat
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -11,6 +11,6 @@ assignees: ''
|
|||||||
|
|
||||||
<!-- What Python feature is missing from RustPython? Give a short description of the feature and how you ran into its absence. -->
|
<!-- What Python feature is missing from RustPython? Give a short description of the feature and how you ran into its absence. -->
|
||||||
|
|
||||||
## Python Documentation
|
## Python Documentation or reference to CPython source code
|
||||||
|
|
||||||
<!-- Give a link to the feature in the CPython documentation (https://docs.python.org/3/) in order to assist in its implementation. -->
|
<!-- Give a link to the feature in the CPython documentation (https://docs.python.org/3/) in order to assist in its implementation. -->
|
||||||
|
|||||||
233
.github/workflows/ci.yaml
vendored
233
.github/workflows/ci.yaml
vendored
@@ -2,7 +2,8 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches: [main, release]
|
branches: [main, release]
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [labeled, unlabeled, opened, synchronize, reopened]
|
types: [unlabeled, opened, synchronize, reopened]
|
||||||
|
merge_group:
|
||||||
|
|
||||||
name: CI
|
name: CI
|
||||||
|
|
||||||
@@ -15,17 +16,23 @@ concurrency:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
CARGO_ARGS: --no-default-features --features stdlib,zlib,importlib,encodings,ssl,jit
|
CARGO_ARGS: --no-default-features --features stdlib,zlib,importlib,encodings,ssl,jit
|
||||||
NON_WASM_PACKAGES: >-
|
# Skip additional tests on Windows. They are checked on Linux and MacOS.
|
||||||
-p rustpython-common
|
WINDOWS_SKIPS: >-
|
||||||
-p rustpython-compiler-core
|
test_glob
|
||||||
-p rustpython-compiler
|
test_importlib
|
||||||
-p rustpython-codegen
|
test_io
|
||||||
-p rustpython-parser
|
test_os
|
||||||
-p rustpython-vm
|
test_pathlib
|
||||||
-p rustpython-stdlib
|
test_posixpath
|
||||||
-p rustpython-jit
|
test_shutil
|
||||||
-p rustpython-derive
|
test_venv
|
||||||
-p rustpython
|
# configparser: https://github.com/RustPython/RustPython/issues/4995#issuecomment-1582397417
|
||||||
|
# socketserver: seems related to configparser crash.
|
||||||
|
MACOS_SKIPS: >-
|
||||||
|
test_configparser
|
||||||
|
test_socketserver
|
||||||
|
# PLATFORM_INDEPENDENT_TESTS are tests that do not depend on the underlying OS. They are currently
|
||||||
|
# only run on Linux to speed up the CI.
|
||||||
PLATFORM_INDEPENDENT_TESTS: >-
|
PLATFORM_INDEPENDENT_TESTS: >-
|
||||||
test_argparse
|
test_argparse
|
||||||
test_array
|
test_array
|
||||||
@@ -97,6 +104,8 @@ env:
|
|||||||
test_unpack
|
test_unpack
|
||||||
test_weakref
|
test_weakref
|
||||||
test_yield_from
|
test_yield_from
|
||||||
|
# Python version targeted by the CI.
|
||||||
|
PYTHON_VERSION: "3.11.4"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
rust_tests:
|
rust_tests:
|
||||||
@@ -104,38 +113,39 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
RUST_BACKTRACE: full
|
RUST_BACKTRACE: full
|
||||||
name: Run rust tests
|
name: Run rust tests
|
||||||
needs: lalrpop
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Cache generated parser
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: compiler/parser/python.rs
|
|
||||||
key: lalrpop-${{ hashFiles('compiler/parser/python.lalrpop') }}
|
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
components: clippy
|
components: clippy
|
||||||
- name: Set up the Windows environment
|
- name: Set up the Windows environment
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
choco install llvm openssl
|
choco install llvm openssl --no-progress
|
||||||
echo "OPENSSL_DIR=C:\Program Files\OpenSSL-Win64" >>$GITHUB_ENV
|
echo "OPENSSL_DIR=C:\Program Files\OpenSSL" >>$GITHUB_ENV
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
- name: Set up the Mac environment
|
- name: Set up the Mac environment
|
||||||
run: brew install autoconf automake libtool
|
run: brew install autoconf automake libtool
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
- uses: Swatinem/rust-cache@v1
|
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
- name: run clippy
|
- name: run clippy
|
||||||
run: cargo clippy ${{ env.CARGO_ARGS }} ${{ env.NON_WASM_PACKAGES }} -- -Dwarnings
|
run: cargo clippy ${{ env.CARGO_ARGS }} --workspace --exclude rustpython_wasm -- -Dwarnings
|
||||||
|
|
||||||
- name: run rust tests
|
- name: run rust tests
|
||||||
run: cargo test --workspace --exclude rustpython_wasm --verbose --features threading ${{ env.CARGO_ARGS }} ${{ env.NON_WASM_PACKAGES }}
|
run: cargo test --workspace --exclude rustpython_wasm --verbose --features threading ${{ env.CARGO_ARGS }}
|
||||||
|
if: runner.os != 'macOS'
|
||||||
|
# temp skip ssl linking for Mac to avoid CI failure
|
||||||
|
- name: run rust tests (MacOS no ssl)
|
||||||
|
run: cargo test --workspace --exclude rustpython_wasm --verbose --no-default-features --features threading,stdlib,zlib,importlib,encodings,jit
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
|
||||||
- name: check compilation without threading
|
- name: check compilation without threading
|
||||||
run: cargo check ${{ env.CARGO_ARGS }}
|
run: cargo check ${{ env.CARGO_ARGS }}
|
||||||
|
|
||||||
@@ -159,16 +169,9 @@ jobs:
|
|||||||
exotic_targets:
|
exotic_targets:
|
||||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip:ci') }}
|
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip:ci') }}
|
||||||
name: Ensure compilation on various targets
|
name: Ensure compilation on various targets
|
||||||
needs: lalrpop
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Cache generated parser
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: compiler/parser/python.rs
|
|
||||||
key: lalrpop-${{ hashFiles('compiler/parser/python.lalrpop') }}
|
|
||||||
|
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
target: i686-unknown-linux-gnu
|
target: i686-unknown-linux-gnu
|
||||||
@@ -185,6 +188,15 @@ jobs:
|
|||||||
- name: Check compilation for android
|
- name: Check compilation for android
|
||||||
run: cargo check --target aarch64-linux-android
|
run: cargo check --target aarch64-linux-android
|
||||||
|
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
target: aarch64-unknown-linux-gnu
|
||||||
|
|
||||||
|
- name: Install gcc-aarch64-linux-gnu
|
||||||
|
run: sudo apt install gcc-aarch64-linux-gnu
|
||||||
|
- name: Check compilation for aarch64 linux gnu
|
||||||
|
run: cargo check --target aarch64-unknown-linux-gnu
|
||||||
|
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
target: i686-unknown-linux-musl
|
target: i686-unknown-linux-musl
|
||||||
@@ -216,14 +228,12 @@ jobs:
|
|||||||
- name: Prepare repository for redox compilation
|
- name: Prepare repository for redox compilation
|
||||||
run: bash scripts/redox/uncomment-cargo.sh
|
run: bash scripts/redox/uncomment-cargo.sh
|
||||||
- name: Check compilation for Redox
|
- name: Check compilation for Redox
|
||||||
if: false # FIXME: redoxer toolchain is from ~july 2021, edition2021 isn't stabilized
|
|
||||||
uses: coolreader18/redoxer-action@v1
|
uses: coolreader18/redoxer-action@v1
|
||||||
with:
|
with:
|
||||||
command: check
|
command: check
|
||||||
|
|
||||||
snippets_cpython:
|
snippets_cpython:
|
||||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip:ci') }}
|
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip:ci') }}
|
||||||
needs: lalrpop
|
|
||||||
env:
|
env:
|
||||||
RUST_BACKTRACE: full
|
RUST_BACKTRACE: full
|
||||||
name: Run snippets and cpython tests
|
name: Run snippets and cpython tests
|
||||||
@@ -233,32 +243,27 @@ jobs:
|
|||||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Cache generated parser
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: compiler/parser/python.rs
|
|
||||||
key: lalrpop-${{ hashFiles('compiler/parser/python.lalrpop') }}
|
|
||||||
|
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
- uses: actions/setup-python@v2
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
- name: Set up the Windows environment
|
- name: Set up the Windows environment
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
choco install llvm openssl
|
choco install llvm openssl --no-progress
|
||||||
echo "OPENSSL_DIR=C:\Program Files\OpenSSL-Win64" >>$GITHUB_ENV
|
echo "OPENSSL_DIR=C:\Program Files\OpenSSL" >>$GITHUB_ENV
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
- name: Set up the Mac environment
|
- name: Set up the Mac environment
|
||||||
run: brew install autoconf automake libtool
|
run: brew install autoconf automake libtool openssl@3
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
- uses: Swatinem/rust-cache@v1
|
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
- name: build rustpython
|
- name: build rustpython
|
||||||
run: cargo build --release --verbose --features=threading ${{ env.CARGO_ARGS }}
|
run: cargo build --release --verbose --features=threading ${{ env.CARGO_ARGS }}
|
||||||
- uses: actions/setup-python@v2
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
- name: run snippets
|
- name: run snippets
|
||||||
run: python -m pip install -r requirements.txt && pytest -v
|
run: python -m pip install -r requirements.txt && pytest -v
|
||||||
working-directory: ./extra_tests
|
working-directory: ./extra_tests
|
||||||
@@ -266,72 +271,39 @@ jobs:
|
|||||||
name: run cpython platform-independent tests
|
name: run cpython platform-independent tests
|
||||||
run:
|
run:
|
||||||
target/release/rustpython -m test -j 1 -u all --slowest --fail-env-changed -v ${{ env.PLATFORM_INDEPENDENT_TESTS }}
|
target/release/rustpython -m test -j 1 -u all --slowest --fail-env-changed -v ${{ env.PLATFORM_INDEPENDENT_TESTS }}
|
||||||
- if: runner.os != 'Windows'
|
- if: runner.os == 'Linux'
|
||||||
name: run cpython platform-dependent tests
|
name: run cpython platform-dependent tests (Linux)
|
||||||
run: target/release/rustpython -m test -j 1 -u all --slowest --fail-env-changed -v -x ${{ env.PLATFORM_INDEPENDENT_TESTS }}
|
run: target/release/rustpython -m test -j 1 -u all --slowest --fail-env-changed -v -x ${{ env.PLATFORM_INDEPENDENT_TESTS }}
|
||||||
|
- if: runner.os == 'macOS'
|
||||||
|
name: run cpython platform-dependent tests (MacOS)
|
||||||
|
run: target/release/rustpython -m test -j 1 -u all --slowest --fail-env-changed -v -x ${{ env.PLATFORM_INDEPENDENT_TESTS }} ${{ env.MACOS_SKIPS }}
|
||||||
- if: runner.os == 'Windows'
|
- if: runner.os == 'Windows'
|
||||||
name: run cpython platform-dependent tests (windows partial - fixme)
|
name: run cpython platform-dependent tests (windows partial - fixme)
|
||||||
run:
|
run:
|
||||||
target/release/rustpython -m test -j 1 -u all --slowest --fail-env-changed -v -x ${{ env.PLATFORM_INDEPENDENT_TESTS }}
|
target/release/rustpython -m test -j 1 -u all --slowest --fail-env-changed -v -x ${{ env.PLATFORM_INDEPENDENT_TESTS }} ${{ env.WINDOWS_SKIPS }}
|
||||||
test_glob
|
|
||||||
test_importlib
|
|
||||||
test_io
|
|
||||||
test_iter
|
|
||||||
test_os
|
|
||||||
test_pathlib
|
|
||||||
test_posixpath
|
|
||||||
test_shutil
|
|
||||||
test_venv
|
|
||||||
- if: runner.os != 'Windows'
|
- if: runner.os != 'Windows'
|
||||||
name: check that --install-pip succeeds
|
name: check that --install-pip succeeds
|
||||||
run: |
|
run: |
|
||||||
mkdir site-packages
|
mkdir site-packages
|
||||||
target/release/rustpython --install-pip ensurepip --user
|
target/release/rustpython --install-pip ensurepip --user
|
||||||
|
- if: runner.os != 'Windows'
|
||||||
lalrpop:
|
name: Check that ensurepip succeeds.
|
||||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip:ci') }}
|
|
||||||
name: Generate parser with lalrpop
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest, windows-latest]
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Cache generated parser
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: compiler/parser/python.rs
|
|
||||||
key: lalrpop-${{ hashFiles('compiler/parser/python.lalrpop') }}
|
|
||||||
- name: Check if cached generated parser exists
|
|
||||||
id: generated_parser
|
|
||||||
uses: andstor/file-existence-action@v1
|
|
||||||
with:
|
|
||||||
files: "compiler/parser/python.rs"
|
|
||||||
- if: runner.os == 'Windows'
|
|
||||||
name: Force python.lalrpop to be lf # actions@checkout ignore .gitattributes
|
|
||||||
run: |
|
run: |
|
||||||
set file compiler/parser/python.lalrpop; ((Get-Content $file) -join "`n") + "`n" | Set-Content -NoNewline $file
|
target/release/rustpython -m ensurepip
|
||||||
- name: Install lalrpop
|
target/release/rustpython -c "import pip"
|
||||||
if: steps.generated_parser.outputs.files_exists == 'false'
|
- if: runner.os != 'Windows'
|
||||||
uses: baptiste0928/cargo-install@v1
|
name: Check if pip inside venv is functional
|
||||||
with:
|
run: |
|
||||||
crate: lalrpop
|
target/release/rustpython -m venv testvenv
|
||||||
version: "0.19.8"
|
testvenv/bin/rustpython -m pip install wheel
|
||||||
- name: Run lalrpop
|
- name: Check whats_left is not broken
|
||||||
if: steps.generated_parser.outputs.files_exists == 'false'
|
run: python -I whats_left.py
|
||||||
run: lalrpop compiler/parser/python.lalrpop
|
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
name: Check Rust code with rustfmt and clippy
|
name: Check Rust code with rustfmt and clippy
|
||||||
needs: lalrpop
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Cache generated parser
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: compiler/parser/python.rs
|
|
||||||
key: lalrpop-${{ hashFiles('compiler/parser/python.lalrpop') }}
|
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
components: rustfmt, clippy
|
components: rustfmt, clippy
|
||||||
@@ -339,40 +311,31 @@ jobs:
|
|||||||
run: cargo fmt --all -- --check
|
run: cargo fmt --all -- --check
|
||||||
- name: run clippy on wasm
|
- name: run clippy on wasm
|
||||||
run: cargo clippy --manifest-path=wasm/lib/Cargo.toml -- -Dwarnings
|
run: cargo clippy --manifest-path=wasm/lib/Cargo.toml -- -Dwarnings
|
||||||
- uses: actions/setup-python@v2
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
- name: install flake8
|
- name: install ruff
|
||||||
run: python -m pip install flake8
|
run: python -m pip install ruff
|
||||||
- name: run lint
|
- name: run python lint
|
||||||
run: flake8 . --count --exclude=./.*,./Lib,./vm/Lib,./benches/ --select=E9,F63,F7,F82 --show-source --statistics
|
run: ruff extra_tests wasm examples --exclude='./.*',./Lib,./vm/Lib,./benches/ --select=E9,F63,F7,F82 --show-source
|
||||||
- name: install prettier
|
- name: install prettier
|
||||||
run: yarn global add prettier && echo "$(yarn global bin)" >>$GITHUB_PATH
|
run: yarn global add prettier && echo "$(yarn global bin)" >>$GITHUB_PATH
|
||||||
- name: check wasm code with prettier
|
- name: check wasm code with prettier
|
||||||
# prettier doesn't handle ignore files very well: https://github.com/prettier/prettier/issues/8506
|
# prettier doesn't handle ignore files very well: https://github.com/prettier/prettier/issues/8506
|
||||||
run: cd wasm && git ls-files -z | xargs -0 prettier --check -u
|
run: cd wasm && git ls-files -z | xargs -0 prettier --check -u
|
||||||
- name: Check update_asdl.sh consistency
|
|
||||||
run: bash scripts/update_asdl.sh && git diff --exit-code
|
|
||||||
- name: Check whats_left is not broken
|
|
||||||
run: python -I whats_left.py
|
|
||||||
|
|
||||||
miri:
|
miri:
|
||||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip:ci') }}
|
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip:ci') }}
|
||||||
name: Run tests under miri
|
name: Run tests under miri
|
||||||
needs: lalrpop
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Cache generated parser
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: compiler/parser/python.rs
|
|
||||||
key: lalrpop-${{ hashFiles('compiler/parser/python.lalrpop') }}
|
|
||||||
- uses: dtolnay/rust-toolchain@master
|
- uses: dtolnay/rust-toolchain@master
|
||||||
with:
|
with:
|
||||||
toolchain: nightly
|
toolchain: nightly
|
||||||
components: miri
|
components: miri
|
||||||
- uses: Swatinem/rust-cache@v1
|
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
- name: Run tests under miri
|
- name: Run tests under miri
|
||||||
# miri-ignore-leaks because the type-object circular reference means that there will always be
|
# miri-ignore-leaks because the type-object circular reference means that there will always be
|
||||||
# a memory leak, at least until we have proper cyclic gc
|
# a memory leak, at least until we have proper cyclic gc
|
||||||
@@ -381,17 +344,12 @@ jobs:
|
|||||||
wasm:
|
wasm:
|
||||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip:ci') }}
|
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip:ci') }}
|
||||||
name: Check the WASM package and demo
|
name: Check the WASM package and demo
|
||||||
needs: lalrpop
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Cache generated parser
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: compiler/parser/python.rs
|
|
||||||
key: lalrpop-${{ hashFiles('compiler/parser/python.lalrpop') }}
|
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
- uses: Swatinem/rust-cache@v1
|
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
- name: install wasm-pack
|
- name: install wasm-pack
|
||||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||||
- name: install geckodriver
|
- name: install geckodriver
|
||||||
@@ -399,17 +357,19 @@ jobs:
|
|||||||
wget https://github.com/mozilla/geckodriver/releases/download/v0.30.0/geckodriver-v0.30.0-linux64.tar.gz
|
wget https://github.com/mozilla/geckodriver/releases/download/v0.30.0/geckodriver-v0.30.0-linux64.tar.gz
|
||||||
mkdir geckodriver
|
mkdir geckodriver
|
||||||
tar -xzf geckodriver-v0.30.0-linux64.tar.gz -C geckodriver
|
tar -xzf geckodriver-v0.30.0-linux64.tar.gz -C geckodriver
|
||||||
- uses: actions/setup-python@v2
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
- run: python -m pip install -r requirements.txt
|
- run: python -m pip install -r requirements.txt
|
||||||
working-directory: ./wasm/tests
|
working-directory: ./wasm/tests
|
||||||
- uses: actions/setup-node@v1
|
- uses: actions/setup-node@v3
|
||||||
- name: run test
|
- name: run test
|
||||||
run: |
|
run: |
|
||||||
export PATH=$PATH:`pwd`/../../geckodriver
|
export PATH=$PATH:`pwd`/../../geckodriver
|
||||||
npm install
|
npm install
|
||||||
npm run test
|
npm run test
|
||||||
|
env:
|
||||||
|
NODE_OPTIONS: "--openssl-legacy-provider"
|
||||||
working-directory: ./wasm/demo
|
working-directory: ./wasm/demo
|
||||||
- name: build notebook demo
|
- name: build notebook demo
|
||||||
if: github.ref == 'refs/heads/release'
|
if: github.ref == 'refs/heads/release'
|
||||||
@@ -417,6 +377,8 @@ jobs:
|
|||||||
npm install
|
npm install
|
||||||
npm run dist
|
npm run dist
|
||||||
mv dist ../demo/dist/notebook
|
mv dist ../demo/dist/notebook
|
||||||
|
env:
|
||||||
|
NODE_OPTIONS: "--openssl-legacy-provider"
|
||||||
working-directory: ./wasm/notebook
|
working-directory: ./wasm/notebook
|
||||||
- name: Deploy demo to Github Pages
|
- name: Deploy demo to Github Pages
|
||||||
if: success() && github.ref == 'refs/heads/release'
|
if: success() && github.ref == 'refs/heads/release'
|
||||||
@@ -430,21 +392,16 @@ jobs:
|
|||||||
wasm-wasi:
|
wasm-wasi:
|
||||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip:ci') }}
|
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip:ci') }}
|
||||||
name: Run snippets and cpython tests on wasm-wasi
|
name: Run snippets and cpython tests on wasm-wasi
|
||||||
needs: lalrpop
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Cache generated parser
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: compiler/parser/python.rs
|
|
||||||
key: lalrpop-${{ hashFiles('compiler/parser/python.lalrpop') }}
|
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
target: wasm32-wasi
|
target: wasm32-wasi
|
||||||
- uses: Swatinem/rust-cache@v1
|
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
- name: Setup Wasmer
|
- name: Setup Wasmer
|
||||||
uses: wasmerio/setup-wasmer@v1
|
uses: wasmerio/setup-wasmer@v2
|
||||||
- name: Install clang
|
- name: Install clang
|
||||||
run: sudo apt-get update && sudo apt-get install clang -y
|
run: sudo apt-get update && sudo apt-get install clang -y
|
||||||
- name: build rustpython
|
- name: build rustpython
|
||||||
|
|||||||
117
.github/workflows/cron-ci.yaml
vendored
117
.github/workflows/cron-ci.yaml
vendored
@@ -6,71 +6,43 @@ on:
|
|||||||
name: Periodic checks/tasks
|
name: Periodic checks/tasks
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CARGO_ARGS: --features ssl,jit
|
CARGO_ARGS: --no-default-features --features stdlib,zlib,importlib,encodings,ssl,jit
|
||||||
|
PYTHON_VERSION: "3.11.4"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
# codecov collects code coverage data from the rust tests, python snippets and python test suite.
|
||||||
|
# This is done using cargo-llvm-cov, which is a wrapper around llvm-cov.
|
||||||
codecov:
|
codecov:
|
||||||
name: Collect code coverage data
|
name: Collect code coverage data
|
||||||
needs: lalrpop
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Cache generated parser
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: compiler/parser/python.rs
|
|
||||||
key: lalrpop-${{ hashFiles('compiler/parser/python.lalrpop') }}
|
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
- uses: taiki-e/install-action@cargo-llvm-cov
|
||||||
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
components: llvm-tools-preview
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
- run: sudo apt-get update && sudo apt-get -y install lcov
|
- run: sudo apt-get update && sudo apt-get -y install lcov
|
||||||
- run: cargo build --release --verbose ${{ env.CARGO_ARGS }}
|
- name: Run cargo-llvm-cov with Rust tests.
|
||||||
env:
|
run: cargo llvm-cov --no-report --workspace --exclude rustpython_wasm --verbose --no-default-features --features stdlib,zlib,importlib,encodings,ssl,jit
|
||||||
RUSTC_WRAPPER: './scripts/codecoverage-rustc-wrapper.sh'
|
- name: Run cargo-llvm-cov with Python snippets.
|
||||||
- uses: actions/setup-python@v2
|
run: python scripts/cargo-llvm-cov.py
|
||||||
with:
|
|
||||||
python-version: "3.10"
|
|
||||||
- run: python -m pip install pytest
|
|
||||||
working-directory: ./extra_tests
|
|
||||||
- name: run snippets
|
|
||||||
run: LLVM_PROFILE_FILE="$PWD/snippet-%p.profraw" pytest -v
|
|
||||||
working-directory: ./extra_tests
|
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
- name: run cpython tests
|
- name: Run cargo-llvm-cov with Python test suite.
|
||||||
run: |
|
run: cargo llvm-cov --no-report run -- -m test -u all --slowest --fail-env-changed
|
||||||
alltests=($(target/release/rustpython -c 'from test.libregrtest.runtest import findtests; print(*findtests())'))
|
|
||||||
i=0
|
|
||||||
# chunk into chunks of 10 tests each. idk at this point
|
|
||||||
while subtests=("${alltests[@]:$i:10}"); [[ ${#subtests[@]} -ne 0 ]]; do
|
|
||||||
LLVM_PROFILE_FILE="$PWD/regrtest-%p.profraw" target/release/rustpython -m test -v "${subtests[@]}" || true
|
|
||||||
((i+=10))
|
|
||||||
done
|
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
- name: prepare code coverage data
|
- name: Prepare code coverage data
|
||||||
run: |
|
run: cargo llvm-cov report --lcov --output-path='codecov.lcov'
|
||||||
rusttool() {
|
- name: Upload to Codecov
|
||||||
local tool=$1; shift; "$(rustc --print target-libdir)/../bin/llvm-$tool" "$@"
|
|
||||||
}
|
|
||||||
rusttool profdata merge extra_tests/snippet-*.profraw regrtest-*.profraw --output codecov.profdata
|
|
||||||
rusttool cov export --instr-profile codecov.profdata target/release/rustpython --format lcov > codecov_tmp.lcov
|
|
||||||
lcov -e codecov_tmp.lcov "$PWD"/'*' -o codecov_tmp2.lcov
|
|
||||||
lcov -r codecov_tmp2.lcov "$PWD"/target/'*' -o codecov.lcov # remove LALRPOP-generated parser
|
|
||||||
- name: upload to Codecov
|
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v3
|
||||||
with:
|
with:
|
||||||
file: ./codecov.lcov
|
file: ./codecov.lcov
|
||||||
|
|
||||||
testdata:
|
testdata:
|
||||||
name: Collect regression test data
|
name: Collect regression test data
|
||||||
needs: lalrpop
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Cache generated parser
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: compiler/parser/python.rs
|
|
||||||
key: lalrpop-${{ hashFiles('compiler/parser/python.lalrpop') }}
|
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
- name: build rustpython
|
- name: build rustpython
|
||||||
run: cargo build --release --verbose
|
run: cargo build --release --verbose
|
||||||
@@ -97,16 +69,13 @@ jobs:
|
|||||||
|
|
||||||
whatsleft:
|
whatsleft:
|
||||||
name: Collect what is left data
|
name: Collect what is left data
|
||||||
needs: lalrpop
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Cache generated parser
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: compiler/parser/python.rs
|
|
||||||
key: lalrpop-${{ hashFiles('compiler/parser/python.lalrpop') }}
|
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
- uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
- name: build rustpython
|
- name: build rustpython
|
||||||
run: cargo build --release --verbose
|
run: cargo build --release --verbose
|
||||||
- name: Collect what is left data
|
- name: Collect what is left data
|
||||||
@@ -135,17 +104,11 @@ jobs:
|
|||||||
|
|
||||||
benchmark:
|
benchmark:
|
||||||
name: Collect benchmark data
|
name: Collect benchmark data
|
||||||
needs: lalrpop
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Cache generated parser
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: compiler/parser/python.rs
|
|
||||||
key: lalrpop-${{ hashFiles('compiler/parser/python.lalrpop') }}
|
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
- uses: actions/setup-python@v2
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: 3.9
|
python-version: 3.9
|
||||||
- run: cargo install cargo-criterion
|
- run: cargo install cargo-criterion
|
||||||
@@ -183,35 +146,3 @@ jobs:
|
|||||||
if git -c user.name="Github Actions" -c user.email="actions@github.com" commit -m "Update benchmark results"; then
|
if git -c user.name="Github Actions" -c user.email="actions@github.com" commit -m "Update benchmark results"; then
|
||||||
git push
|
git push
|
||||||
fi
|
fi
|
||||||
|
|
||||||
lalrpop:
|
|
||||||
name: Generate parser with lalrpop
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest, windows-latest]
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Cache generated parser
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: compiler/parser/python.rs
|
|
||||||
key: lalrpop-${{ hashFiles('compiler/parser/python.lalrpop') }}
|
|
||||||
- name: Check if cached generated parser exists
|
|
||||||
id: generated_parser
|
|
||||||
uses: andstor/file-existence-action@v1
|
|
||||||
with:
|
|
||||||
files: "compiler/parser/python.rs"
|
|
||||||
- if: runner.os == 'Windows'
|
|
||||||
name: Force python.lalrpop to be lf # actions@checkout ignore .gitattributes
|
|
||||||
run: |
|
|
||||||
set file compiler/parser/python.lalrpop; ((Get-Content $file) -join "`n") + "`n" | Set-Content -NoNewline $file
|
|
||||||
- name: Install lalrpop
|
|
||||||
if: steps.generated_parser.outputs.files_exists == 'false'
|
|
||||||
uses: baptiste0928/cargo-install@v1
|
|
||||||
with:
|
|
||||||
crate: lalrpop
|
|
||||||
version: "0.19.8"
|
|
||||||
- name: Run lalrpop
|
|
||||||
if: steps.generated_parser.outputs.files_exists == 'false'
|
|
||||||
run: lalrpop compiler/parser/python.lalrpop
|
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -19,5 +19,3 @@ flamescope.json
|
|||||||
|
|
||||||
extra_tests/snippets/resources
|
extra_tests/snippets/resources
|
||||||
extra_tests/not_impl.py
|
extra_tests/not_impl.py
|
||||||
|
|
||||||
compiler/parser/python.rs
|
|
||||||
|
|||||||
21
.vscode/launch.json
vendored
21
.vscode/launch.json
vendored
@@ -8,15 +8,24 @@
|
|||||||
"type": "lldb",
|
"type": "lldb",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Debug executable 'rustpython'",
|
"name": "Debug executable 'rustpython'",
|
||||||
"cargo": {
|
|
||||||
"args": [
|
|
||||||
"build",
|
|
||||||
"--package=rustpython"
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"preLaunchTask": "Build RustPython Debug",
|
"preLaunchTask": "Build RustPython Debug",
|
||||||
"program": "target/debug/rustpython",
|
"program": "target/debug/rustpython",
|
||||||
"args": [],
|
"args": [],
|
||||||
|
"env": {
|
||||||
|
"RUST_BACKTRACE": "1"
|
||||||
|
},
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug executable 'rustpython' without SSL",
|
||||||
|
"preLaunchTask": "Build RustPython Debug without SSL",
|
||||||
|
"program": "target/debug/rustpython",
|
||||||
|
"args": [],
|
||||||
|
"env": {
|
||||||
|
"RUST_BACKTRACE": "1"
|
||||||
|
},
|
||||||
"cwd": "${workspaceFolder}"
|
"cwd": "${workspaceFolder}"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
20
.vscode/tasks.json
vendored
20
.vscode/tasks.json
vendored
@@ -2,7 +2,7 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"label": "Build RustPython Debug",
|
"label": "Build RustPython Debug without SSL",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "cargo",
|
"command": "cargo",
|
||||||
"args": [
|
"args": [
|
||||||
@@ -15,6 +15,22 @@
|
|||||||
"kind": "build",
|
"kind": "build",
|
||||||
"isDefault": true,
|
"isDefault": true,
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
"label": "Build RustPython Debug",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "cargo",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--features=ssl"
|
||||||
|
],
|
||||||
|
"problemMatcher": [
|
||||||
|
"$rustc",
|
||||||
|
],
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
1179
Cargo.lock
generated
1179
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
106
Cargo.toml
106
Cargo.toml
@@ -1,11 +1,9 @@
|
|||||||
# REDOX START
|
|
||||||
# cargo-features = ["edition2021"]
|
|
||||||
# REDOX END
|
|
||||||
[package]
|
[package]
|
||||||
name = "rustpython"
|
name = "rustpython"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
authors = ["RustPython Team"]
|
authors = ["RustPython Team"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
rust-version = "1.67.1"
|
||||||
description = "A python interpreter written in rust."
|
description = "A python interpreter written in rust."
|
||||||
repository = "https://github.com/RustPython/RustPython"
|
repository = "https://github.com/RustPython/RustPython"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
@@ -14,15 +12,78 @@ include = ["LICENSE", "Cargo.toml", "src/**/*.rs"]
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
"compiler", "compiler/ast", "compiler/core", "compiler/codegen", "compiler/parser",
|
"compiler", "compiler/core", "compiler/codegen",
|
||||||
".", "common", "derive", "jit", "vm", "pylib", "stdlib", "wasm/lib", "derive-impl",
|
".", "common", "derive", "jit", "vm", "pylib", "stdlib", "wasm/lib", "derive-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
|
rustpython-compiler-core = { path = "compiler/core", version = "0.3.0" }
|
||||||
|
rustpython-compiler = { path = "compiler", version = "0.3.0" }
|
||||||
|
rustpython-codegen = { path = "compiler/codegen", version = "0.3.0" }
|
||||||
|
rustpython-common = { path = "common", version = "0.3.0" }
|
||||||
|
rustpython-derive = { path = "derive", version = "0.3.0" }
|
||||||
|
rustpython-derive-impl = { path = "derive-impl", version = "0.3.0" }
|
||||||
|
rustpython-jit = { path = "jit", version = "0.3.0" }
|
||||||
|
rustpython-vm = { path = "vm", version = "0.3.0" }
|
||||||
|
rustpython-pylib = { path = "pylib", version = "0.3.0" }
|
||||||
|
rustpython-stdlib = { path = "stdlib", version = "0.3.0" }
|
||||||
|
rustpython-doc = { git = "https://github.com/RustPython/__doc__", tag = "0.3.0", version = "0.3.0" }
|
||||||
|
|
||||||
|
rustpython-literal = { git = "https://github.com/RustPython/Parser.git", tag = "0.3.0", version = "0.3.0" }
|
||||||
|
rustpython-parser-core = { git = "https://github.com/RustPython/Parser.git", tag = "0.3.0", version = "0.3.0" }
|
||||||
|
rustpython-parser = { git = "https://github.com/RustPython/Parser.git", tag = "0.3.0", version = "0.3.0" }
|
||||||
|
rustpython-ast = { git = "https://github.com/RustPython/Parser.git", tag = "0.3.0", version = "0.3.0" }
|
||||||
|
rustpython-format = { git = "https://github.com/RustPython/Parser.git", tag = "0.3.0", version = "0.3.0" }
|
||||||
|
# rustpython-literal = { path = "../RustPython-parser/literal" }
|
||||||
|
# rustpython-parser-core = { path = "../RustPython-parser/core" }
|
||||||
|
# rustpython-parser = { path = "../RustPython-parser/parser" }
|
||||||
|
# rustpython-ast = { path = "../RustPython-parser/ast" }
|
||||||
|
# rustpython-format = { path = "../RustPython-parser/format" }
|
||||||
|
|
||||||
|
ahash = "0.7.6"
|
||||||
|
anyhow = "1.0.45"
|
||||||
|
ascii = "1.0"
|
||||||
|
atty = "0.2.14"
|
||||||
|
bitflags = "2.2.1"
|
||||||
|
bstr = "0.2.17"
|
||||||
|
cfg-if = "1.0"
|
||||||
|
chrono = "0.4.19"
|
||||||
|
crossbeam-utils = "0.8.16"
|
||||||
|
flame = "0.2.2"
|
||||||
|
glob = "0.3"
|
||||||
|
hex = "0.4.3"
|
||||||
|
indexmap = "1.8.1"
|
||||||
|
insta = "1.14.0"
|
||||||
|
itertools = "0.10.3"
|
||||||
|
libc = "0.2.133"
|
||||||
|
log = "0.4.16"
|
||||||
|
nix = "0.26"
|
||||||
|
malachite-bigint = { version = "0.1.0" }
|
||||||
|
malachite-q = "0.3.2"
|
||||||
|
malachite-base = "0.3.2"
|
||||||
|
num-complex = "0.4.0"
|
||||||
|
num-integer = "0.1.44"
|
||||||
|
num-traits = "0.2"
|
||||||
|
num_enum = "0.5.7"
|
||||||
|
once_cell = "1.13"
|
||||||
|
parking_lot = "0.12"
|
||||||
|
paste = "1.0.7"
|
||||||
|
rand = "0.8.5"
|
||||||
|
rustyline = "11"
|
||||||
|
serde = "1.0"
|
||||||
|
schannel = "0.1.19"
|
||||||
|
static_assertions = "1.1"
|
||||||
|
syn = "1.0.91"
|
||||||
|
thiserror = "1.0"
|
||||||
|
thread_local = "1.1.4"
|
||||||
|
unicode_names2 = { version = "0.6.0", git = "https://github.com/youknowone/unicode_names2.git", rev = "4ce16aa85cbcdd9cc830410f1a72ef9a235f2fde" }
|
||||||
|
widestring = "0.5.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["threading", "stdlib", "zlib", "importlib", "encodings", "rustpython-parser/lalrpop"]
|
default = ["threading", "stdlib", "zlib", "importlib"]
|
||||||
importlib = ["rustpython-vm/importlib"]
|
importlib = ["rustpython-vm/importlib"]
|
||||||
encodings = ["rustpython-vm/encodings"]
|
encodings = ["rustpython-vm/encodings"]
|
||||||
stdlib = ["rustpython-stdlib", "rustpython-pylib"]
|
stdlib = ["rustpython-stdlib", "rustpython-pylib", "encodings"]
|
||||||
flame-it = ["rustpython-vm/flame-it", "flame", "flamescope"]
|
flame-it = ["rustpython-vm/flame-it", "flame", "flamescope"]
|
||||||
freeze-stdlib = ["rustpython-vm/freeze-stdlib", "rustpython-pylib?/freeze-stdlib"]
|
freeze-stdlib = ["rustpython-vm/freeze-stdlib", "rustpython-pylib?/freeze-stdlib"]
|
||||||
jit = ["rustpython-vm/jit"]
|
jit = ["rustpython-vm/jit"]
|
||||||
@@ -33,30 +94,32 @@ ssl = ["rustpython-stdlib/ssl"]
|
|||||||
ssl-vendor = ["rustpython-stdlib/ssl-vendor"]
|
ssl-vendor = ["rustpython-stdlib/ssl-vendor"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rustpython-compiler = { path = "compiler", version = "0.2.0" }
|
rustpython-compiler = { workspace = true }
|
||||||
rustpython-parser = { path = "compiler/parser", version = "0.2.0" }
|
rustpython-pylib = { workspace = true, optional = true }
|
||||||
rustpython-pylib = { path = "pylib", optional = true, default-features = false }
|
rustpython-stdlib = { workspace = true, optional = true }
|
||||||
rustpython-stdlib = { path = "stdlib", optional = true, default-features = false }
|
rustpython-vm = { workspace = true, default-features = false, features = ["compiler"] }
|
||||||
rustpython-vm = { path = "vm", version = "0.2.0", default-features = false, features = ["compiler"] }
|
rustpython-parser = { workspace = true }
|
||||||
|
|
||||||
|
atty = { workspace = true }
|
||||||
|
cfg-if = { workspace = true }
|
||||||
|
log = { workspace = true }
|
||||||
|
flame = { workspace = true, optional = true }
|
||||||
|
|
||||||
cfg-if = "1.0.0"
|
|
||||||
clap = "2.34"
|
clap = "2.34"
|
||||||
dirs = { package = "dirs-next", version = "2.0.0" }
|
dirs = { package = "dirs-next", version = "2.0.0" }
|
||||||
env_logger = { version = "0.9.0", default-features = false, features = ["atty", "termcolor"] }
|
env_logger = { version = "0.9.0", default-features = false, features = ["atty", "termcolor"] }
|
||||||
flame = { version = "0.2.2", optional = true }
|
|
||||||
flamescope = { version = "0.1.2", optional = true }
|
flamescope = { version = "0.1.2", optional = true }
|
||||||
libc = "0.2.133"
|
|
||||||
log = "0.4.16"
|
[target.'cfg(windows)'.dependencies]
|
||||||
num-traits = "0.2.14"
|
libc = { workspace = true }
|
||||||
atty = "0.2.14"
|
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
rustyline = "10.0.0"
|
rustyline = { workspace = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
cpython = "0.7.0"
|
cpython = "0.7.0"
|
||||||
criterion = "0.3.5"
|
criterion = "0.3.5"
|
||||||
python3-sys = "0.7.0"
|
python3-sys = "0.7.1"
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "execution"
|
name = "execution"
|
||||||
@@ -87,5 +150,6 @@ opt-level = 3
|
|||||||
lto = "thin"
|
lto = "thin"
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
# REDOX START, Uncommment when you want to compile/check with redoxer
|
# REDOX START, Uncomment when you want to compile/check with redoxer
|
||||||
|
# nix = { git = "https://github.com/coolreader18/nix", branch = "0.26.2-redox" }
|
||||||
# REDOX END
|
# REDOX END
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ The contents of the Development Guide include:
|
|||||||
|
|
||||||
RustPython requires the following:
|
RustPython requires the following:
|
||||||
|
|
||||||
- Rust latest stable version (e.g 1.51.0 as of Apr 2 2021)
|
- Rust latest stable version (e.g 1.69.0 as of Apr 20 2023)
|
||||||
- To check Rust version: `rustc --version`
|
- To check Rust version: `rustc --version`
|
||||||
- If you have `rustup` on your system, enter to update to the latest
|
- If you have `rustup` on your system, enter to update to the latest
|
||||||
stable version: `rustup update stable`
|
stable version: `rustup update stable`
|
||||||
- If you do not have Rust installed, use [rustup](https://rustup.rs/) to
|
- If you do not have Rust installed, use [rustup](https://rustup.rs/) to
|
||||||
do so.
|
do so.
|
||||||
- CPython version 3.10 or higher
|
- CPython version 3.11 or higher
|
||||||
- CPython can be installed by your operating system's package manager,
|
- CPython can be installed by your operating system's package manager,
|
||||||
from the [Python website](https://www.python.org/downloads/), or
|
from the [Python website](https://www.python.org/downloads/), or
|
||||||
using a third-party distribution, such as
|
using a third-party distribution, such as
|
||||||
@@ -47,7 +47,10 @@ you can check yourself with `cargo clippy`.
|
|||||||
|
|
||||||
Custom Python code (i.e. code not copied from CPython's standard library) should
|
Custom Python code (i.e. code not copied from CPython's standard library) should
|
||||||
follow the [PEP 8](https://www.python.org/dev/peps/pep-0008/) style. We also use
|
follow the [PEP 8](https://www.python.org/dev/peps/pep-0008/) style. We also use
|
||||||
[flake8](http://flake8.pycqa.org/en/latest/) to check Python code style.
|
[ruff](https://beta.ruff.rs/docs/) to check Python code style.
|
||||||
|
|
||||||
|
In addition to language specific tools, [cspell](https://github.com/streetsidesoftware/cspell),
|
||||||
|
a code spell checker, is used in order to ensure correct spellings for code.
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
|
|||||||
16
Lib/__hello__.py
vendored
Normal file
16
Lib/__hello__.py
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
initialized = True
|
||||||
|
|
||||||
|
class TestFrozenUtf8_1:
|
||||||
|
"""\u00b6"""
|
||||||
|
|
||||||
|
class TestFrozenUtf8_2:
|
||||||
|
"""\u03c0"""
|
||||||
|
|
||||||
|
class TestFrozenUtf8_4:
|
||||||
|
"""\U0001f600"""
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("Hello world!")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
7
Lib/__phello__/__init__.py
vendored
Normal file
7
Lib/__phello__/__init__.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
initialized = True
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("Hello world!")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
0
Lib/__phello__/ham/eggs.py
vendored
Normal file
0
Lib/__phello__/ham/eggs.py
vendored
Normal file
7
Lib/__phello__/spam.py
vendored
Normal file
7
Lib/__phello__/spam.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
initialized = True
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("Hello world!")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
68
Lib/_collections_abc.py
vendored
68
Lib/_collections_abc.py
vendored
@@ -430,25 +430,13 @@ class _CallableGenericAlias(GenericAlias):
|
|||||||
raise TypeError(
|
raise TypeError(
|
||||||
"Callable must be used as Callable[[arg, ...], result].")
|
"Callable must be used as Callable[[arg, ...], result].")
|
||||||
t_args, t_result = args
|
t_args, t_result = args
|
||||||
if isinstance(t_args, list):
|
if isinstance(t_args, (tuple, list)):
|
||||||
args = (*t_args, t_result)
|
args = (*t_args, t_result)
|
||||||
elif not _is_param_expr(t_args):
|
elif not _is_param_expr(t_args):
|
||||||
raise TypeError(f"Expected a list of types, an ellipsis, "
|
raise TypeError(f"Expected a list of types, an ellipsis, "
|
||||||
f"ParamSpec, or Concatenate. Got {t_args}")
|
f"ParamSpec, or Concatenate. Got {t_args}")
|
||||||
return super().__new__(cls, origin, args)
|
return super().__new__(cls, origin, args)
|
||||||
|
|
||||||
@property
|
|
||||||
def __parameters__(self):
|
|
||||||
params = []
|
|
||||||
for arg in self.__args__:
|
|
||||||
# Looks like a genericalias
|
|
||||||
if hasattr(arg, "__parameters__") and isinstance(arg.__parameters__, tuple):
|
|
||||||
params.extend(arg.__parameters__)
|
|
||||||
else:
|
|
||||||
if _is_typevarlike(arg):
|
|
||||||
params.append(arg)
|
|
||||||
return tuple(dict.fromkeys(params))
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
if len(self.__args__) == 2 and _is_param_expr(self.__args__[0]):
|
if len(self.__args__) == 2 and _is_param_expr(self.__args__[0]):
|
||||||
return super().__repr__()
|
return super().__repr__()
|
||||||
@@ -468,54 +456,24 @@ class _CallableGenericAlias(GenericAlias):
|
|||||||
# code is copied from typing's _GenericAlias and the builtin
|
# code is copied from typing's _GenericAlias and the builtin
|
||||||
# types.GenericAlias.
|
# types.GenericAlias.
|
||||||
|
|
||||||
# A special case in PEP 612 where if X = Callable[P, int],
|
|
||||||
# then X[int, str] == X[[int, str]].
|
|
||||||
param_len = len(self.__parameters__)
|
|
||||||
if param_len == 0:
|
|
||||||
raise TypeError(f'{self} is not a generic class')
|
|
||||||
if not isinstance(item, tuple):
|
if not isinstance(item, tuple):
|
||||||
item = (item,)
|
item = (item,)
|
||||||
if (param_len == 1 and _is_param_expr(self.__parameters__[0])
|
# A special case in PEP 612 where if X = Callable[P, int],
|
||||||
|
# then X[int, str] == X[[int, str]].
|
||||||
|
if (len(self.__parameters__) == 1
|
||||||
|
and _is_param_expr(self.__parameters__[0])
|
||||||
and item and not _is_param_expr(item[0])):
|
and item and not _is_param_expr(item[0])):
|
||||||
item = (list(item),)
|
item = (item,)
|
||||||
item_len = len(item)
|
|
||||||
if item_len != param_len:
|
new_args = super().__getitem__(item).__args__
|
||||||
raise TypeError(f'Too {"many" if item_len > param_len else "few"}'
|
|
||||||
f' arguments for {self};'
|
|
||||||
f' actual {item_len}, expected {param_len}')
|
|
||||||
subst = dict(zip(self.__parameters__, item))
|
|
||||||
new_args = []
|
|
||||||
for arg in self.__args__:
|
|
||||||
if _is_typevarlike(arg):
|
|
||||||
if _is_param_expr(arg):
|
|
||||||
arg = subst[arg]
|
|
||||||
if not _is_param_expr(arg):
|
|
||||||
raise TypeError(f"Expected a list of types, an ellipsis, "
|
|
||||||
f"ParamSpec, or Concatenate. Got {arg}")
|
|
||||||
else:
|
|
||||||
arg = subst[arg]
|
|
||||||
# Looks like a GenericAlias
|
|
||||||
elif hasattr(arg, '__parameters__') and isinstance(arg.__parameters__, tuple):
|
|
||||||
subparams = arg.__parameters__
|
|
||||||
if subparams:
|
|
||||||
subargs = tuple(subst[x] for x in subparams)
|
|
||||||
arg = arg[subargs]
|
|
||||||
new_args.append(arg)
|
|
||||||
|
|
||||||
# args[0] occurs due to things like Z[[int, str, bool]] from PEP 612
|
# args[0] occurs due to things like Z[[int, str, bool]] from PEP 612
|
||||||
if not isinstance(new_args[0], list):
|
if not isinstance(new_args[0], (tuple, list)):
|
||||||
t_result = new_args[-1]
|
t_result = new_args[-1]
|
||||||
t_args = new_args[:-1]
|
t_args = new_args[:-1]
|
||||||
new_args = (t_args, t_result)
|
new_args = (t_args, t_result)
|
||||||
return _CallableGenericAlias(Callable, tuple(new_args))
|
return _CallableGenericAlias(Callable, tuple(new_args))
|
||||||
|
|
||||||
|
|
||||||
def _is_typevarlike(arg):
|
|
||||||
obj = type(arg)
|
|
||||||
# looks like a TypeVar/ParamSpec
|
|
||||||
return (obj.__module__ == 'typing'
|
|
||||||
and obj.__name__ in {'ParamSpec', 'TypeVar'})
|
|
||||||
|
|
||||||
def _is_param_expr(obj):
|
def _is_param_expr(obj):
|
||||||
"""Checks if obj matches either a list of types, ``...``, ``ParamSpec`` or
|
"""Checks if obj matches either a list of types, ``...``, ``ParamSpec`` or
|
||||||
``_ConcatenateGenericAlias`` from typing.py
|
``_ConcatenateGenericAlias`` from typing.py
|
||||||
@@ -868,7 +826,7 @@ class KeysView(MappingView, Set):
|
|||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _from_iterable(self, it):
|
def _from_iterable(cls, it):
|
||||||
return set(it)
|
return set(it)
|
||||||
|
|
||||||
def __contains__(self, key):
|
def __contains__(self, key):
|
||||||
@@ -886,7 +844,7 @@ class ItemsView(MappingView, Set):
|
|||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _from_iterable(self, it):
|
def _from_iterable(cls, it):
|
||||||
return set(it)
|
return set(it)
|
||||||
|
|
||||||
def __contains__(self, item):
|
def __contains__(self, item):
|
||||||
@@ -1064,10 +1022,10 @@ class Sequence(Reversible, Collection):
|
|||||||
while stop is None or i < stop:
|
while stop is None or i < stop:
|
||||||
try:
|
try:
|
||||||
v = self[i]
|
v = self[i]
|
||||||
if v is value or v == value:
|
|
||||||
return i
|
|
||||||
except IndexError:
|
except IndexError:
|
||||||
break
|
break
|
||||||
|
if v is value or v == value:
|
||||||
|
return i
|
||||||
i += 1
|
i += 1
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
|
|||||||
12
Lib/_compression.py
vendored
12
Lib/_compression.py
vendored
@@ -1,7 +1,7 @@
|
|||||||
"""Internal classes used by the gzip, lzma and bz2 modules"""
|
"""Internal classes used by the gzip, lzma and bz2 modules"""
|
||||||
|
|
||||||
import io
|
import io
|
||||||
|
import sys
|
||||||
|
|
||||||
BUFFER_SIZE = io.DEFAULT_BUFFER_SIZE # Compressed data read chunk size
|
BUFFER_SIZE = io.DEFAULT_BUFFER_SIZE # Compressed data read chunk size
|
||||||
|
|
||||||
@@ -110,6 +110,16 @@ class DecompressReader(io.RawIOBase):
|
|||||||
self._pos += len(data)
|
self._pos += len(data)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
def readall(self):
|
||||||
|
chunks = []
|
||||||
|
# sys.maxsize means the max length of output buffer is unlimited,
|
||||||
|
# so that the whole input buffer can be decompressed within one
|
||||||
|
# .decompress() call.
|
||||||
|
while data := self.read(sys.maxsize):
|
||||||
|
chunks.append(data)
|
||||||
|
|
||||||
|
return b"".join(chunks)
|
||||||
|
|
||||||
# Rewind the file to the beginning of the data stream.
|
# Rewind the file to the beginning of the data stream.
|
||||||
def _rewind(self):
|
def _rewind(self):
|
||||||
self._fp.seek(0)
|
self._fp.seek(0)
|
||||||
|
|||||||
3
Lib/_dummy_thread.py
vendored
3
Lib/_dummy_thread.py
vendored
@@ -145,6 +145,9 @@ class LockType(object):
|
|||||||
def locked(self):
|
def locked(self):
|
||||||
return self.locked_status
|
return self.locked_status
|
||||||
|
|
||||||
|
def _at_fork_reinit(self):
|
||||||
|
self.locked_status = False
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s %s.%s object at %s>" % (
|
return "<%s %s.%s object at %s>" % (
|
||||||
"locked" if self.locked_status else "unlocked",
|
"locked" if self.locked_status else "unlocked",
|
||||||
|
|||||||
35
Lib/_markupbase.py
vendored
35
Lib/_markupbase.py
vendored
@@ -29,10 +29,6 @@ class ParserBase:
|
|||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"_markupbase.ParserBase must be subclassed")
|
"_markupbase.ParserBase must be subclassed")
|
||||||
|
|
||||||
def error(self, message):
|
|
||||||
raise NotImplementedError(
|
|
||||||
"subclasses of ParserBase must override error()")
|
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self.lineno = 1
|
self.lineno = 1
|
||||||
self.offset = 0
|
self.offset = 0
|
||||||
@@ -131,12 +127,11 @@ class ParserBase:
|
|||||||
# also in data attribute specifications of attlist declaration
|
# also in data attribute specifications of attlist declaration
|
||||||
# also link type declaration subsets in linktype declarations
|
# also link type declaration subsets in linktype declarations
|
||||||
# also link attribute specification lists in link declarations
|
# also link attribute specification lists in link declarations
|
||||||
self.error("unsupported '[' char in %s declaration" % decltype)
|
raise AssertionError("unsupported '[' char in %s declaration" % decltype)
|
||||||
else:
|
else:
|
||||||
self.error("unexpected '[' char in declaration")
|
raise AssertionError("unexpected '[' char in declaration")
|
||||||
else:
|
else:
|
||||||
self.error(
|
raise AssertionError("unexpected %r char in declaration" % rawdata[j])
|
||||||
"unexpected %r char in declaration" % rawdata[j])
|
|
||||||
if j < 0:
|
if j < 0:
|
||||||
return j
|
return j
|
||||||
return -1 # incomplete
|
return -1 # incomplete
|
||||||
@@ -156,7 +151,9 @@ class ParserBase:
|
|||||||
# look for MS Office ]> ending
|
# look for MS Office ]> ending
|
||||||
match= _msmarkedsectionclose.search(rawdata, i+3)
|
match= _msmarkedsectionclose.search(rawdata, i+3)
|
||||||
else:
|
else:
|
||||||
self.error('unknown status keyword %r in marked section' % rawdata[i+3:j])
|
raise AssertionError(
|
||||||
|
'unknown status keyword %r in marked section' % rawdata[i+3:j]
|
||||||
|
)
|
||||||
if not match:
|
if not match:
|
||||||
return -1
|
return -1
|
||||||
if report:
|
if report:
|
||||||
@@ -168,7 +165,7 @@ class ParserBase:
|
|||||||
def parse_comment(self, i, report=1):
|
def parse_comment(self, i, report=1):
|
||||||
rawdata = self.rawdata
|
rawdata = self.rawdata
|
||||||
if rawdata[i:i+4] != '<!--':
|
if rawdata[i:i+4] != '<!--':
|
||||||
self.error('unexpected call to parse_comment()')
|
raise AssertionError('unexpected call to parse_comment()')
|
||||||
match = _commentclose.search(rawdata, i+4)
|
match = _commentclose.search(rawdata, i+4)
|
||||||
if not match:
|
if not match:
|
||||||
return -1
|
return -1
|
||||||
@@ -192,7 +189,9 @@ class ParserBase:
|
|||||||
return -1
|
return -1
|
||||||
if s != "<!":
|
if s != "<!":
|
||||||
self.updatepos(declstartpos, j + 1)
|
self.updatepos(declstartpos, j + 1)
|
||||||
self.error("unexpected char in internal subset (in %r)" % s)
|
raise AssertionError(
|
||||||
|
"unexpected char in internal subset (in %r)" % s
|
||||||
|
)
|
||||||
if (j + 2) == n:
|
if (j + 2) == n:
|
||||||
# end of buffer; incomplete
|
# end of buffer; incomplete
|
||||||
return -1
|
return -1
|
||||||
@@ -209,8 +208,9 @@ class ParserBase:
|
|||||||
return -1
|
return -1
|
||||||
if name not in {"attlist", "element", "entity", "notation"}:
|
if name not in {"attlist", "element", "entity", "notation"}:
|
||||||
self.updatepos(declstartpos, j + 2)
|
self.updatepos(declstartpos, j + 2)
|
||||||
self.error(
|
raise AssertionError(
|
||||||
"unknown declaration %r in internal subset" % name)
|
"unknown declaration %r in internal subset" % name
|
||||||
|
)
|
||||||
# handle the individual names
|
# handle the individual names
|
||||||
meth = getattr(self, "_parse_doctype_" + name)
|
meth = getattr(self, "_parse_doctype_" + name)
|
||||||
j = meth(j, declstartpos)
|
j = meth(j, declstartpos)
|
||||||
@@ -234,14 +234,14 @@ class ParserBase:
|
|||||||
if rawdata[j] == ">":
|
if rawdata[j] == ">":
|
||||||
return j
|
return j
|
||||||
self.updatepos(declstartpos, j)
|
self.updatepos(declstartpos, j)
|
||||||
self.error("unexpected char after internal subset")
|
raise AssertionError("unexpected char after internal subset")
|
||||||
else:
|
else:
|
||||||
return -1
|
return -1
|
||||||
elif c.isspace():
|
elif c.isspace():
|
||||||
j = j + 1
|
j = j + 1
|
||||||
else:
|
else:
|
||||||
self.updatepos(declstartpos, j)
|
self.updatepos(declstartpos, j)
|
||||||
self.error("unexpected char %r in internal subset" % c)
|
raise AssertionError("unexpected char %r in internal subset" % c)
|
||||||
# end of buffer reached
|
# end of buffer reached
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
@@ -387,8 +387,9 @@ class ParserBase:
|
|||||||
return name.lower(), m.end()
|
return name.lower(), m.end()
|
||||||
else:
|
else:
|
||||||
self.updatepos(declstartpos, i)
|
self.updatepos(declstartpos, i)
|
||||||
self.error("expected name token at %r"
|
raise AssertionError(
|
||||||
% rawdata[declstartpos:declstartpos+20])
|
"expected name token at %r" % rawdata[declstartpos:declstartpos+20]
|
||||||
|
)
|
||||||
|
|
||||||
# To be overridden -- handlers for unknown objects
|
# To be overridden -- handlers for unknown objects
|
||||||
def unknown_decl(self, data):
|
def unknown_decl(self, data):
|
||||||
|
|||||||
2
Lib/abc.py
vendored
2
Lib/abc.py
vendored
@@ -106,7 +106,7 @@ else:
|
|||||||
implementations defined by the registering ABC be callable (not
|
implementations defined by the registering ABC be callable (not
|
||||||
even via super()).
|
even via super()).
|
||||||
"""
|
"""
|
||||||
def __new__(mcls, name, bases, namespace, **kwargs):
|
def __new__(mcls, name, bases, namespace, /, **kwargs):
|
||||||
cls = super().__new__(mcls, name, bases, namespace, **kwargs)
|
cls = super().__new__(mcls, name, bases, namespace, **kwargs)
|
||||||
_abc_init(cls)
|
_abc_init(cls)
|
||||||
return cls
|
return cls
|
||||||
|
|||||||
65
Lib/aifc.py
vendored
65
Lib/aifc.py
vendored
@@ -138,7 +138,11 @@ import struct
|
|||||||
import builtins
|
import builtins
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
__all__ = ["Error", "open", "openfp"]
|
__all__ = ["Error", "open"]
|
||||||
|
|
||||||
|
|
||||||
|
warnings._deprecated(__name__, remove=(3, 13))
|
||||||
|
|
||||||
|
|
||||||
class Error(Exception):
|
class Error(Exception):
|
||||||
pass
|
pass
|
||||||
@@ -251,7 +255,9 @@ def _write_float(f, x):
|
|||||||
_write_ulong(f, himant)
|
_write_ulong(f, himant)
|
||||||
_write_ulong(f, lomant)
|
_write_ulong(f, lomant)
|
||||||
|
|
||||||
from chunk import Chunk
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter("ignore", DeprecationWarning)
|
||||||
|
from chunk import Chunk
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
_aifc_params = namedtuple('_aifc_params',
|
_aifc_params = namedtuple('_aifc_params',
|
||||||
@@ -447,21 +453,33 @@ class Aifc_read:
|
|||||||
#
|
#
|
||||||
|
|
||||||
def _alaw2lin(self, data):
|
def _alaw2lin(self, data):
|
||||||
import audioop
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter('ignore', category=DeprecationWarning)
|
||||||
|
import audioop
|
||||||
return audioop.alaw2lin(data, 2)
|
return audioop.alaw2lin(data, 2)
|
||||||
|
|
||||||
def _ulaw2lin(self, data):
|
def _ulaw2lin(self, data):
|
||||||
import audioop
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter('ignore', category=DeprecationWarning)
|
||||||
|
import audioop
|
||||||
return audioop.ulaw2lin(data, 2)
|
return audioop.ulaw2lin(data, 2)
|
||||||
|
|
||||||
def _adpcm2lin(self, data):
|
def _adpcm2lin(self, data):
|
||||||
import audioop
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter('ignore', category=DeprecationWarning)
|
||||||
|
import audioop
|
||||||
if not hasattr(self, '_adpcmstate'):
|
if not hasattr(self, '_adpcmstate'):
|
||||||
# first time
|
# first time
|
||||||
self._adpcmstate = None
|
self._adpcmstate = None
|
||||||
data, self._adpcmstate = audioop.adpcm2lin(data, 2, self._adpcmstate)
|
data, self._adpcmstate = audioop.adpcm2lin(data, 2, self._adpcmstate)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
def _sowt2lin(self, data):
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter('ignore', category=DeprecationWarning)
|
||||||
|
import audioop
|
||||||
|
return audioop.byteswap(data, 2)
|
||||||
|
|
||||||
def _read_comm_chunk(self, chunk):
|
def _read_comm_chunk(self, chunk):
|
||||||
self._nchannels = _read_short(chunk)
|
self._nchannels = _read_short(chunk)
|
||||||
self._nframes = _read_long(chunk)
|
self._nframes = _read_long(chunk)
|
||||||
@@ -497,6 +515,8 @@ class Aifc_read:
|
|||||||
self._convert = self._ulaw2lin
|
self._convert = self._ulaw2lin
|
||||||
elif self._comptype in (b'alaw', b'ALAW'):
|
elif self._comptype in (b'alaw', b'ALAW'):
|
||||||
self._convert = self._alaw2lin
|
self._convert = self._alaw2lin
|
||||||
|
elif self._comptype in (b'sowt', b'SOWT'):
|
||||||
|
self._convert = self._sowt2lin
|
||||||
else:
|
else:
|
||||||
raise Error('unsupported compression type')
|
raise Error('unsupported compression type')
|
||||||
self._sampwidth = 2
|
self._sampwidth = 2
|
||||||
@@ -659,7 +679,7 @@ class Aifc_write:
|
|||||||
if self._nframeswritten:
|
if self._nframeswritten:
|
||||||
raise Error('cannot change parameters after starting to write')
|
raise Error('cannot change parameters after starting to write')
|
||||||
if comptype not in (b'NONE', b'ulaw', b'ULAW',
|
if comptype not in (b'NONE', b'ulaw', b'ULAW',
|
||||||
b'alaw', b'ALAW', b'G722'):
|
b'alaw', b'ALAW', b'G722', b'sowt', b'SOWT'):
|
||||||
raise Error('unsupported compression type')
|
raise Error('unsupported compression type')
|
||||||
self._comptype = comptype
|
self._comptype = comptype
|
||||||
self._compname = compname
|
self._compname = compname
|
||||||
@@ -680,7 +700,7 @@ class Aifc_write:
|
|||||||
if self._nframeswritten:
|
if self._nframeswritten:
|
||||||
raise Error('cannot change parameters after starting to write')
|
raise Error('cannot change parameters after starting to write')
|
||||||
if comptype not in (b'NONE', b'ulaw', b'ULAW',
|
if comptype not in (b'NONE', b'ulaw', b'ULAW',
|
||||||
b'alaw', b'ALAW', b'G722'):
|
b'alaw', b'ALAW', b'G722', b'sowt', b'SOWT'):
|
||||||
raise Error('unsupported compression type')
|
raise Error('unsupported compression type')
|
||||||
self.setnchannels(nchannels)
|
self.setnchannels(nchannels)
|
||||||
self.setsampwidth(sampwidth)
|
self.setsampwidth(sampwidth)
|
||||||
@@ -764,28 +784,43 @@ class Aifc_write:
|
|||||||
#
|
#
|
||||||
|
|
||||||
def _lin2alaw(self, data):
|
def _lin2alaw(self, data):
|
||||||
import audioop
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter('ignore', category=DeprecationWarning)
|
||||||
|
import audioop
|
||||||
return audioop.lin2alaw(data, 2)
|
return audioop.lin2alaw(data, 2)
|
||||||
|
|
||||||
def _lin2ulaw(self, data):
|
def _lin2ulaw(self, data):
|
||||||
import audioop
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter('ignore', category=DeprecationWarning)
|
||||||
|
import audioop
|
||||||
return audioop.lin2ulaw(data, 2)
|
return audioop.lin2ulaw(data, 2)
|
||||||
|
|
||||||
def _lin2adpcm(self, data):
|
def _lin2adpcm(self, data):
|
||||||
import audioop
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter('ignore', category=DeprecationWarning)
|
||||||
|
import audioop
|
||||||
if not hasattr(self, '_adpcmstate'):
|
if not hasattr(self, '_adpcmstate'):
|
||||||
self._adpcmstate = None
|
self._adpcmstate = None
|
||||||
data, self._adpcmstate = audioop.lin2adpcm(data, 2, self._adpcmstate)
|
data, self._adpcmstate = audioop.lin2adpcm(data, 2, self._adpcmstate)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
def _lin2sowt(self, data):
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter('ignore', category=DeprecationWarning)
|
||||||
|
import audioop
|
||||||
|
return audioop.byteswap(data, 2)
|
||||||
|
|
||||||
def _ensure_header_written(self, datasize):
|
def _ensure_header_written(self, datasize):
|
||||||
if not self._nframeswritten:
|
if not self._nframeswritten:
|
||||||
if self._comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'):
|
if self._comptype in (b'ULAW', b'ulaw',
|
||||||
|
b'ALAW', b'alaw', b'G722',
|
||||||
|
b'sowt', b'SOWT'):
|
||||||
if not self._sampwidth:
|
if not self._sampwidth:
|
||||||
self._sampwidth = 2
|
self._sampwidth = 2
|
||||||
if self._sampwidth != 2:
|
if self._sampwidth != 2:
|
||||||
raise Error('sample width must be 2 when compressing '
|
raise Error('sample width must be 2 when compressing '
|
||||||
'with ulaw/ULAW, alaw/ALAW or G7.22 (ADPCM)')
|
'with ulaw/ULAW, alaw/ALAW, sowt/SOWT '
|
||||||
|
'or G7.22 (ADPCM)')
|
||||||
if not self._nchannels:
|
if not self._nchannels:
|
||||||
raise Error('# channels not specified')
|
raise Error('# channels not specified')
|
||||||
if not self._sampwidth:
|
if not self._sampwidth:
|
||||||
@@ -801,6 +836,8 @@ class Aifc_write:
|
|||||||
self._convert = self._lin2ulaw
|
self._convert = self._lin2ulaw
|
||||||
elif self._comptype in (b'alaw', b'ALAW'):
|
elif self._comptype in (b'alaw', b'ALAW'):
|
||||||
self._convert = self._lin2alaw
|
self._convert = self._lin2alaw
|
||||||
|
elif self._comptype in (b'sowt', b'SOWT'):
|
||||||
|
self._convert = self._lin2sowt
|
||||||
|
|
||||||
def _write_header(self, initlength):
|
def _write_header(self, initlength):
|
||||||
if self._aifc and self._comptype != b'NONE':
|
if self._aifc and self._comptype != b'NONE':
|
||||||
@@ -920,10 +957,6 @@ def open(f, mode=None):
|
|||||||
else:
|
else:
|
||||||
raise Error("mode must be 'r', 'rb', 'w', or 'wb'")
|
raise Error("mode must be 'r', 'rb', 'w', or 'wb'")
|
||||||
|
|
||||||
def openfp(f, mode=None):
|
|
||||||
warnings.warn("aifc.openfp is deprecated since Python 3.7. "
|
|
||||||
"Use aifc.open instead.", DeprecationWarning, stacklevel=2)
|
|
||||||
return open(f, mode=mode)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys
|
import sys
|
||||||
|
|||||||
4
Lib/antigravity.py
vendored
4
Lib/antigravity.py
vendored
@@ -11,7 +11,7 @@ def geohash(latitude, longitude, datedow):
|
|||||||
37.857713 -122.544543
|
37.857713 -122.544543
|
||||||
|
|
||||||
'''
|
'''
|
||||||
# http://xkcd.com/426/
|
# https://xkcd.com/426/
|
||||||
h = hashlib.md5(datedow).hexdigest()
|
h = hashlib.md5(datedow, usedforsecurity=False).hexdigest()
|
||||||
p, q = [('%f' % float.fromhex('0.' + x)) for x in (h[:16], h[16:32])]
|
p, q = [('%f' % float.fromhex('0.' + x)) for x in (h[:16], h[16:32])]
|
||||||
print('%d%s %d%s' % (latitude, p[1:], longitude, q[1:]))
|
print('%d%s %d%s' % (latitude, p[1:], longitude, q[1:]))
|
||||||
|
|||||||
68
Lib/argparse.py
vendored
68
Lib/argparse.py
vendored
@@ -89,6 +89,8 @@ import os as _os
|
|||||||
import re as _re
|
import re as _re
|
||||||
import sys as _sys
|
import sys as _sys
|
||||||
|
|
||||||
|
import warnings
|
||||||
|
|
||||||
from gettext import gettext as _, ngettext
|
from gettext import gettext as _, ngettext
|
||||||
|
|
||||||
SUPPRESS = '==SUPPRESS=='
|
SUPPRESS = '==SUPPRESS=='
|
||||||
@@ -151,6 +153,7 @@ def _copy_items(items):
|
|||||||
# Formatting Help
|
# Formatting Help
|
||||||
# ===============
|
# ===============
|
||||||
|
|
||||||
|
|
||||||
class HelpFormatter(object):
|
class HelpFormatter(object):
|
||||||
"""Formatter for generating usage messages and argument help strings.
|
"""Formatter for generating usage messages and argument help strings.
|
||||||
|
|
||||||
@@ -693,8 +696,19 @@ class ArgumentDefaultsHelpFormatter(HelpFormatter):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def _get_help_string(self, action):
|
def _get_help_string(self, action):
|
||||||
|
"""
|
||||||
|
Add the default value to the option help message.
|
||||||
|
|
||||||
|
ArgumentDefaultsHelpFormatter and BooleanOptionalAction when it isn't
|
||||||
|
already present. This code will do that, detecting cornercases to
|
||||||
|
prevent duplicates or cases where it wouldn't make sense to the end
|
||||||
|
user.
|
||||||
|
"""
|
||||||
help = action.help
|
help = action.help
|
||||||
if '%(default)' not in action.help:
|
if help is None:
|
||||||
|
help = ''
|
||||||
|
|
||||||
|
if '%(default)' not in help:
|
||||||
if action.default is not SUPPRESS:
|
if action.default is not SUPPRESS:
|
||||||
defaulting_nargs = [OPTIONAL, ZERO_OR_MORE]
|
defaulting_nargs = [OPTIONAL, ZERO_OR_MORE]
|
||||||
if action.option_strings or action.nargs in defaulting_nargs:
|
if action.option_strings or action.nargs in defaulting_nargs:
|
||||||
@@ -702,6 +716,7 @@ class ArgumentDefaultsHelpFormatter(HelpFormatter):
|
|||||||
return help
|
return help
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MetavarTypeHelpFormatter(HelpFormatter):
|
class MetavarTypeHelpFormatter(HelpFormatter):
|
||||||
"""Help message formatter which uses the argument 'type' as the default
|
"""Help message formatter which uses the argument 'type' as the default
|
||||||
metavar value (instead of the argument 'dest')
|
metavar value (instead of the argument 'dest')
|
||||||
@@ -717,7 +732,6 @@ class MetavarTypeHelpFormatter(HelpFormatter):
|
|||||||
return action.type.__name__
|
return action.type.__name__
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# =====================
|
# =====================
|
||||||
# Options and Arguments
|
# Options and Arguments
|
||||||
# =====================
|
# =====================
|
||||||
@@ -752,7 +766,7 @@ class ArgumentError(Exception):
|
|||||||
if self.argument_name is None:
|
if self.argument_name is None:
|
||||||
format = '%(message)s'
|
format = '%(message)s'
|
||||||
else:
|
else:
|
||||||
format = 'argument %(argument_name)s: %(message)s'
|
format = _('argument %(argument_name)s: %(message)s')
|
||||||
return format % dict(message=self.message,
|
return format % dict(message=self.message,
|
||||||
argument_name=self.argument_name)
|
argument_name=self.argument_name)
|
||||||
|
|
||||||
@@ -860,6 +874,7 @@ class Action(_AttributeHolder):
|
|||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
raise NotImplementedError(_('.__call__() not defined'))
|
raise NotImplementedError(_('.__call__() not defined'))
|
||||||
|
|
||||||
|
|
||||||
class BooleanOptionalAction(Action):
|
class BooleanOptionalAction(Action):
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
option_strings,
|
option_strings,
|
||||||
@@ -879,9 +894,6 @@ class BooleanOptionalAction(Action):
|
|||||||
option_string = '--no-' + option_string[2:]
|
option_string = '--no-' + option_string[2:]
|
||||||
_option_strings.append(option_string)
|
_option_strings.append(option_string)
|
||||||
|
|
||||||
if help is not None and default is not None and default is not SUPPRESS:
|
|
||||||
help += " (default: %(default)s)"
|
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
option_strings=_option_strings,
|
option_strings=_option_strings,
|
||||||
dest=dest,
|
dest=dest,
|
||||||
@@ -893,6 +905,7 @@ class BooleanOptionalAction(Action):
|
|||||||
help=help,
|
help=help,
|
||||||
metavar=metavar)
|
metavar=metavar)
|
||||||
|
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
if option_string in self.option_strings:
|
if option_string in self.option_strings:
|
||||||
setattr(namespace, self.dest, not option_string.startswith('--no-'))
|
setattr(namespace, self.dest, not option_string.startswith('--no-'))
|
||||||
@@ -941,7 +954,7 @@ class _StoreConstAction(Action):
|
|||||||
def __init__(self,
|
def __init__(self,
|
||||||
option_strings,
|
option_strings,
|
||||||
dest,
|
dest,
|
||||||
const,
|
const=None,
|
||||||
default=None,
|
default=None,
|
||||||
required=False,
|
required=False,
|
||||||
help=None,
|
help=None,
|
||||||
@@ -1036,7 +1049,7 @@ class _AppendConstAction(Action):
|
|||||||
def __init__(self,
|
def __init__(self,
|
||||||
option_strings,
|
option_strings,
|
||||||
dest,
|
dest,
|
||||||
const,
|
const=None,
|
||||||
default=None,
|
default=None,
|
||||||
required=False,
|
required=False,
|
||||||
help=None,
|
help=None,
|
||||||
@@ -1168,6 +1181,13 @@ class _SubParsersAction(Action):
|
|||||||
|
|
||||||
aliases = kwargs.pop('aliases', ())
|
aliases = kwargs.pop('aliases', ())
|
||||||
|
|
||||||
|
if name in self._name_parser_map:
|
||||||
|
raise ArgumentError(self, _('conflicting subparser: %s') % name)
|
||||||
|
for alias in aliases:
|
||||||
|
if alias in self._name_parser_map:
|
||||||
|
raise ArgumentError(
|
||||||
|
self, _('conflicting subparser alias: %s') % alias)
|
||||||
|
|
||||||
# create a pseudo-action to hold the choice help
|
# create a pseudo-action to hold the choice help
|
||||||
if 'help' in kwargs:
|
if 'help' in kwargs:
|
||||||
help = kwargs.pop('help')
|
help = kwargs.pop('help')
|
||||||
@@ -1648,6 +1668,14 @@ class _ArgumentGroup(_ActionsContainer):
|
|||||||
super(_ArgumentGroup, self)._remove_action(action)
|
super(_ArgumentGroup, self)._remove_action(action)
|
||||||
self._group_actions.remove(action)
|
self._group_actions.remove(action)
|
||||||
|
|
||||||
|
def add_argument_group(self, *args, **kwargs):
|
||||||
|
warnings.warn(
|
||||||
|
"Nesting argument groups is deprecated.",
|
||||||
|
category=DeprecationWarning,
|
||||||
|
stacklevel=2
|
||||||
|
)
|
||||||
|
return super().add_argument_group(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class _MutuallyExclusiveGroup(_ArgumentGroup):
|
class _MutuallyExclusiveGroup(_ArgumentGroup):
|
||||||
|
|
||||||
@@ -1668,6 +1696,14 @@ class _MutuallyExclusiveGroup(_ArgumentGroup):
|
|||||||
self._container._remove_action(action)
|
self._container._remove_action(action)
|
||||||
self._group_actions.remove(action)
|
self._group_actions.remove(action)
|
||||||
|
|
||||||
|
def add_mutually_exclusive_group(self, *args, **kwargs):
|
||||||
|
warnings.warn(
|
||||||
|
"Nesting mutually exclusive groups is deprecated.",
|
||||||
|
category=DeprecationWarning,
|
||||||
|
stacklevel=2
|
||||||
|
)
|
||||||
|
return super().add_mutually_exclusive_group(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||||
"""Object for parsing command line strings into Python objects.
|
"""Object for parsing command line strings into Python objects.
|
||||||
@@ -1857,8 +1893,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||||||
if self.exit_on_error:
|
if self.exit_on_error:
|
||||||
try:
|
try:
|
||||||
namespace, args = self._parse_known_args(args, namespace)
|
namespace, args = self._parse_known_args(args, namespace)
|
||||||
except ArgumentError:
|
except ArgumentError as err:
|
||||||
err = _sys.exc_info()[1]
|
|
||||||
self.error(str(err))
|
self.error(str(err))
|
||||||
else:
|
else:
|
||||||
namespace, args = self._parse_known_args(args, namespace)
|
namespace, args = self._parse_known_args(args, namespace)
|
||||||
@@ -1962,7 +1997,11 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||||||
# arguments, try to parse more single-dash options out
|
# arguments, try to parse more single-dash options out
|
||||||
# of the tail of the option string
|
# of the tail of the option string
|
||||||
chars = self.prefix_chars
|
chars = self.prefix_chars
|
||||||
if arg_count == 0 and option_string[1] not in chars:
|
if (
|
||||||
|
arg_count == 0
|
||||||
|
and option_string[1] not in chars
|
||||||
|
and explicit_arg != ''
|
||||||
|
):
|
||||||
action_tuples.append((action, [], option_string))
|
action_tuples.append((action, [], option_string))
|
||||||
char = option_string[0]
|
char = option_string[0]
|
||||||
option_string = char + explicit_arg[0]
|
option_string = char + explicit_arg[0]
|
||||||
@@ -2133,8 +2172,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||||||
arg_strings.append(arg)
|
arg_strings.append(arg)
|
||||||
arg_strings = self._read_args_from_files(arg_strings)
|
arg_strings = self._read_args_from_files(arg_strings)
|
||||||
new_arg_strings.extend(arg_strings)
|
new_arg_strings.extend(arg_strings)
|
||||||
except OSError:
|
except OSError as err:
|
||||||
err = _sys.exc_info()[1]
|
|
||||||
self.error(str(err))
|
self.error(str(err))
|
||||||
|
|
||||||
# return the modified argument list
|
# return the modified argument list
|
||||||
@@ -2484,9 +2522,9 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||||||
result = type_func(arg_string)
|
result = type_func(arg_string)
|
||||||
|
|
||||||
# ArgumentTypeErrors indicate errors
|
# ArgumentTypeErrors indicate errors
|
||||||
except ArgumentTypeError:
|
except ArgumentTypeError as err:
|
||||||
name = getattr(action.type, '__name__', repr(action.type))
|
name = getattr(action.type, '__name__', repr(action.type))
|
||||||
msg = str(_sys.exc_info()[1])
|
msg = str(err)
|
||||||
raise ArgumentError(action, msg)
|
raise ArgumentError(action, msg)
|
||||||
|
|
||||||
# TypeErrors or ValueErrors also indicate errors
|
# TypeErrors or ValueErrors also indicate errors
|
||||||
|
|||||||
12
Lib/ast.py
vendored
12
Lib/ast.py
vendored
@@ -53,10 +53,12 @@ def parse(source, filename='<unknown>', mode='exec', *,
|
|||||||
|
|
||||||
def literal_eval(node_or_string):
|
def literal_eval(node_or_string):
|
||||||
"""
|
"""
|
||||||
Safely evaluate an expression node or a string containing a Python
|
Evaluate an expression node or a string containing only a Python
|
||||||
expression. The string or node provided may only consist of the following
|
expression. The string or node provided may only consist of the following
|
||||||
Python literal structures: strings, bytes, numbers, tuples, lists, dicts,
|
Python literal structures: strings, bytes, numbers, tuples, lists, dicts,
|
||||||
sets, booleans, and None.
|
sets, booleans, and None.
|
||||||
|
|
||||||
|
Caution: A complex expression can overflow the C stack and cause a crash.
|
||||||
"""
|
"""
|
||||||
if isinstance(node_or_string, str):
|
if isinstance(node_or_string, str):
|
||||||
node_or_string = parse(node_or_string.lstrip(" \t"), mode='eval')
|
node_or_string = parse(node_or_string.lstrip(" \t"), mode='eval')
|
||||||
@@ -234,6 +236,12 @@ def increment_lineno(node, n=1):
|
|||||||
location in a file.
|
location in a file.
|
||||||
"""
|
"""
|
||||||
for child in walk(node):
|
for child in walk(node):
|
||||||
|
# TypeIgnore is a special case where lineno is not an attribute
|
||||||
|
# but rather a field of the node itself.
|
||||||
|
if isinstance(child, TypeIgnore):
|
||||||
|
child.lineno = getattr(child, 'lineno', 0) + n
|
||||||
|
continue
|
||||||
|
|
||||||
if 'lineno' in child._attributes:
|
if 'lineno' in child._attributes:
|
||||||
child.lineno = getattr(child, 'lineno', 0) + n
|
child.lineno = getattr(child, 'lineno', 0) + n
|
||||||
if (
|
if (
|
||||||
@@ -849,7 +857,7 @@ class _Unparser(NodeVisitor):
|
|||||||
|
|
||||||
def visit_ImportFrom(self, node):
|
def visit_ImportFrom(self, node):
|
||||||
self.fill("from ")
|
self.fill("from ")
|
||||||
self.write("." * node.level)
|
self.write("." * (node.level or 0))
|
||||||
if node.module:
|
if node.module:
|
||||||
self.write(node.module)
|
self.write(node.module)
|
||||||
self.write(" import ")
|
self.write(" import ")
|
||||||
|
|||||||
136
Lib/base64.py
vendored
136
Lib/base64.py
vendored
@@ -1,4 +1,4 @@
|
|||||||
#! /usr/bin/python3.6
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
"""Base16, Base32, Base64 (RFC 3548), Base85 and Ascii85 data encodings"""
|
"""Base16, Base32, Base64 (RFC 3548), Base85 and Ascii85 data encodings"""
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ __all__ = [
|
|||||||
'encode', 'decode', 'encodebytes', 'decodebytes',
|
'encode', 'decode', 'encodebytes', 'decodebytes',
|
||||||
# Generalized interface for other encodings
|
# Generalized interface for other encodings
|
||||||
'b64encode', 'b64decode', 'b32encode', 'b32decode',
|
'b64encode', 'b64decode', 'b32encode', 'b32decode',
|
||||||
'b16encode', 'b16decode',
|
'b32hexencode', 'b32hexdecode', 'b16encode', 'b16decode',
|
||||||
# Base85 and Ascii85 encodings
|
# Base85 and Ascii85 encodings
|
||||||
'b85encode', 'b85decode', 'a85encode', 'a85decode',
|
'b85encode', 'b85decode', 'a85encode', 'a85decode',
|
||||||
# Standard Base64 encoding
|
# Standard Base64 encoding
|
||||||
@@ -76,15 +76,16 @@ def b64decode(s, altchars=None, validate=False):
|
|||||||
normal base-64 alphabet nor the alternative alphabet are discarded prior
|
normal base-64 alphabet nor the alternative alphabet are discarded prior
|
||||||
to the padding check. If validate is True, these non-alphabet characters
|
to the padding check. If validate is True, these non-alphabet characters
|
||||||
in the input result in a binascii.Error.
|
in the input result in a binascii.Error.
|
||||||
|
For more information about the strict base64 check, see:
|
||||||
|
|
||||||
|
https://docs.python.org/3.11/library/binascii.html#binascii.a2b_base64
|
||||||
"""
|
"""
|
||||||
s = _bytes_from_decode_data(s)
|
s = _bytes_from_decode_data(s)
|
||||||
if altchars is not None:
|
if altchars is not None:
|
||||||
altchars = _bytes_from_decode_data(altchars)
|
altchars = _bytes_from_decode_data(altchars)
|
||||||
assert len(altchars) == 2, repr(altchars)
|
assert len(altchars) == 2, repr(altchars)
|
||||||
s = s.translate(bytes.maketrans(altchars, b'+/'))
|
s = s.translate(bytes.maketrans(altchars, b'+/'))
|
||||||
if validate and not re.match(b'^[A-Za-z0-9+/]*={0,2}$', s):
|
return binascii.a2b_base64(s, strict_mode=validate)
|
||||||
raise binascii.Error('Non-base64 digit found')
|
|
||||||
return binascii.a2b_base64(s)
|
|
||||||
|
|
||||||
|
|
||||||
def standard_b64encode(s):
|
def standard_b64encode(s):
|
||||||
@@ -135,19 +136,40 @@ def urlsafe_b64decode(s):
|
|||||||
|
|
||||||
|
|
||||||
# Base32 encoding/decoding must be done in Python
|
# Base32 encoding/decoding must be done in Python
|
||||||
_b32alphabet = b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
|
_B32_ENCODE_DOCSTRING = '''
|
||||||
_b32tab2 = None
|
Encode the bytes-like objects using {encoding} and return a bytes object.
|
||||||
_b32rev = None
|
'''
|
||||||
|
_B32_DECODE_DOCSTRING = '''
|
||||||
|
Decode the {encoding} encoded bytes-like object or ASCII string s.
|
||||||
|
|
||||||
def b32encode(s):
|
Optional casefold is a flag specifying whether a lowercase alphabet is
|
||||||
"""Encode the bytes-like object s using Base32 and return a bytes object.
|
acceptable as input. For security purposes, the default is False.
|
||||||
"""
|
{extra_args}
|
||||||
|
The result is returned as a bytes object. A binascii.Error is raised if
|
||||||
|
the input is incorrectly padded or if there are non-alphabet
|
||||||
|
characters present in the input.
|
||||||
|
'''
|
||||||
|
_B32_DECODE_MAP01_DOCSTRING = '''
|
||||||
|
RFC 3548 allows for optional mapping of the digit 0 (zero) to the
|
||||||
|
letter O (oh), and for optional mapping of the digit 1 (one) to
|
||||||
|
either the letter I (eye) or letter L (el). The optional argument
|
||||||
|
map01 when not None, specifies which letter the digit 1 should be
|
||||||
|
mapped to (when map01 is not None, the digit 0 is always mapped to
|
||||||
|
the letter O). For security purposes the default is None, so that
|
||||||
|
0 and 1 are not allowed in the input.
|
||||||
|
'''
|
||||||
|
_b32alphabet = b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
|
||||||
|
_b32hexalphabet = b'0123456789ABCDEFGHIJKLMNOPQRSTUV'
|
||||||
|
_b32tab2 = {}
|
||||||
|
_b32rev = {}
|
||||||
|
|
||||||
|
def _b32encode(alphabet, s):
|
||||||
global _b32tab2
|
global _b32tab2
|
||||||
# Delay the initialization of the table to not waste memory
|
# Delay the initialization of the table to not waste memory
|
||||||
# if the function is never called
|
# if the function is never called
|
||||||
if _b32tab2 is None:
|
if alphabet not in _b32tab2:
|
||||||
b32tab = [bytes((i,)) for i in _b32alphabet]
|
b32tab = [bytes((i,)) for i in alphabet]
|
||||||
_b32tab2 = [a + b for a in b32tab for b in b32tab]
|
_b32tab2[alphabet] = [a + b for a in b32tab for b in b32tab]
|
||||||
b32tab = None
|
b32tab = None
|
||||||
|
|
||||||
if not isinstance(s, bytes_types):
|
if not isinstance(s, bytes_types):
|
||||||
@@ -158,9 +180,9 @@ def b32encode(s):
|
|||||||
s = s + b'\0' * (5 - leftover) # Don't use += !
|
s = s + b'\0' * (5 - leftover) # Don't use += !
|
||||||
encoded = bytearray()
|
encoded = bytearray()
|
||||||
from_bytes = int.from_bytes
|
from_bytes = int.from_bytes
|
||||||
b32tab2 = _b32tab2
|
b32tab2 = _b32tab2[alphabet]
|
||||||
for i in range(0, len(s), 5):
|
for i in range(0, len(s), 5):
|
||||||
c = from_bytes(s[i: i + 5], 'big')
|
c = from_bytes(s[i: i + 5]) # big endian
|
||||||
encoded += (b32tab2[c >> 30] + # bits 1 - 10
|
encoded += (b32tab2[c >> 30] + # bits 1 - 10
|
||||||
b32tab2[(c >> 20) & 0x3ff] + # bits 11 - 20
|
b32tab2[(c >> 20) & 0x3ff] + # bits 11 - 20
|
||||||
b32tab2[(c >> 10) & 0x3ff] + # bits 21 - 30
|
b32tab2[(c >> 10) & 0x3ff] + # bits 21 - 30
|
||||||
@@ -177,29 +199,12 @@ def b32encode(s):
|
|||||||
encoded[-1:] = b'='
|
encoded[-1:] = b'='
|
||||||
return bytes(encoded)
|
return bytes(encoded)
|
||||||
|
|
||||||
def b32decode(s, casefold=False, map01=None):
|
def _b32decode(alphabet, s, casefold=False, map01=None):
|
||||||
"""Decode the Base32 encoded bytes-like object or ASCII string s.
|
|
||||||
|
|
||||||
Optional casefold is a flag specifying whether a lowercase alphabet is
|
|
||||||
acceptable as input. For security purposes, the default is False.
|
|
||||||
|
|
||||||
RFC 3548 allows for optional mapping of the digit 0 (zero) to the
|
|
||||||
letter O (oh), and for optional mapping of the digit 1 (one) to
|
|
||||||
either the letter I (eye) or letter L (el). The optional argument
|
|
||||||
map01 when not None, specifies which letter the digit 1 should be
|
|
||||||
mapped to (when map01 is not None, the digit 0 is always mapped to
|
|
||||||
the letter O). For security purposes the default is None, so that
|
|
||||||
0 and 1 are not allowed in the input.
|
|
||||||
|
|
||||||
The result is returned as a bytes object. A binascii.Error is raised if
|
|
||||||
the input is incorrectly padded or if there are non-alphabet
|
|
||||||
characters present in the input.
|
|
||||||
"""
|
|
||||||
global _b32rev
|
global _b32rev
|
||||||
# Delay the initialization of the table to not waste memory
|
# Delay the initialization of the table to not waste memory
|
||||||
# if the function is never called
|
# if the function is never called
|
||||||
if _b32rev is None:
|
if alphabet not in _b32rev:
|
||||||
_b32rev = {v: k for k, v in enumerate(_b32alphabet)}
|
_b32rev[alphabet] = {v: k for k, v in enumerate(alphabet)}
|
||||||
s = _bytes_from_decode_data(s)
|
s = _bytes_from_decode_data(s)
|
||||||
if len(s) % 8:
|
if len(s) % 8:
|
||||||
raise binascii.Error('Incorrect padding')
|
raise binascii.Error('Incorrect padding')
|
||||||
@@ -220,7 +225,7 @@ def b32decode(s, casefold=False, map01=None):
|
|||||||
padchars = l - len(s)
|
padchars = l - len(s)
|
||||||
# Now decode the full quanta
|
# Now decode the full quanta
|
||||||
decoded = bytearray()
|
decoded = bytearray()
|
||||||
b32rev = _b32rev
|
b32rev = _b32rev[alphabet]
|
||||||
for i in range(0, len(s), 8):
|
for i in range(0, len(s), 8):
|
||||||
quanta = s[i: i + 8]
|
quanta = s[i: i + 8]
|
||||||
acc = 0
|
acc = 0
|
||||||
@@ -229,18 +234,38 @@ def b32decode(s, casefold=False, map01=None):
|
|||||||
acc = (acc << 5) + b32rev[c]
|
acc = (acc << 5) + b32rev[c]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise binascii.Error('Non-base32 digit found') from None
|
raise binascii.Error('Non-base32 digit found') from None
|
||||||
decoded += acc.to_bytes(5, 'big')
|
decoded += acc.to_bytes(5) # big endian
|
||||||
# Process the last, partial quanta
|
# Process the last, partial quanta
|
||||||
if l % 8 or padchars not in {0, 1, 3, 4, 6}:
|
if l % 8 or padchars not in {0, 1, 3, 4, 6}:
|
||||||
raise binascii.Error('Incorrect padding')
|
raise binascii.Error('Incorrect padding')
|
||||||
if padchars and decoded:
|
if padchars and decoded:
|
||||||
acc <<= 5 * padchars
|
acc <<= 5 * padchars
|
||||||
last = acc.to_bytes(5, 'big')
|
last = acc.to_bytes(5) # big endian
|
||||||
leftover = (43 - 5 * padchars) // 8 # 1: 4, 3: 3, 4: 2, 6: 1
|
leftover = (43 - 5 * padchars) // 8 # 1: 4, 3: 3, 4: 2, 6: 1
|
||||||
decoded[-5:] = last[:leftover]
|
decoded[-5:] = last[:leftover]
|
||||||
return bytes(decoded)
|
return bytes(decoded)
|
||||||
|
|
||||||
|
|
||||||
|
def b32encode(s):
|
||||||
|
return _b32encode(_b32alphabet, s)
|
||||||
|
b32encode.__doc__ = _B32_ENCODE_DOCSTRING.format(encoding='base32')
|
||||||
|
|
||||||
|
def b32decode(s, casefold=False, map01=None):
|
||||||
|
return _b32decode(_b32alphabet, s, casefold, map01)
|
||||||
|
b32decode.__doc__ = _B32_DECODE_DOCSTRING.format(encoding='base32',
|
||||||
|
extra_args=_B32_DECODE_MAP01_DOCSTRING)
|
||||||
|
|
||||||
|
def b32hexencode(s):
|
||||||
|
return _b32encode(_b32hexalphabet, s)
|
||||||
|
b32hexencode.__doc__ = _B32_ENCODE_DOCSTRING.format(encoding='base32hex')
|
||||||
|
|
||||||
|
def b32hexdecode(s, casefold=False):
|
||||||
|
# base32hex does not have the 01 mapping
|
||||||
|
return _b32decode(_b32hexalphabet, s, casefold)
|
||||||
|
b32hexdecode.__doc__ = _B32_DECODE_DOCSTRING.format(encoding='base32hex',
|
||||||
|
extra_args='')
|
||||||
|
|
||||||
|
|
||||||
# RFC 3548, Base 16 Alphabet specifies uppercase, but hexlify() returns
|
# RFC 3548, Base 16 Alphabet specifies uppercase, but hexlify() returns
|
||||||
# lowercase. The RFC also recommends against accepting input case
|
# lowercase. The RFC also recommends against accepting input case
|
||||||
# insensitively.
|
# insensitively.
|
||||||
@@ -320,7 +345,7 @@ def a85encode(b, *, foldspaces=False, wrapcol=0, pad=False, adobe=False):
|
|||||||
global _a85chars, _a85chars2
|
global _a85chars, _a85chars2
|
||||||
# Delay the initialization of tables to not waste memory
|
# Delay the initialization of tables to not waste memory
|
||||||
# if the function is never called
|
# if the function is never called
|
||||||
if _a85chars is None:
|
if _a85chars2 is None:
|
||||||
_a85chars = [bytes((i,)) for i in range(33, 118)]
|
_a85chars = [bytes((i,)) for i in range(33, 118)]
|
||||||
_a85chars2 = [(a + b) for a in _a85chars for b in _a85chars]
|
_a85chars2 = [(a + b) for a in _a85chars for b in _a85chars]
|
||||||
|
|
||||||
@@ -428,7 +453,7 @@ def b85encode(b, pad=False):
|
|||||||
global _b85chars, _b85chars2
|
global _b85chars, _b85chars2
|
||||||
# Delay the initialization of tables to not waste memory
|
# Delay the initialization of tables to not waste memory
|
||||||
# if the function is never called
|
# if the function is never called
|
||||||
if _b85chars is None:
|
if _b85chars2 is None:
|
||||||
_b85chars = [bytes((i,)) for i in _b85alphabet]
|
_b85chars = [bytes((i,)) for i in _b85alphabet]
|
||||||
_b85chars2 = [(a + b) for a in _b85chars for b in _b85chars]
|
_b85chars2 = [(a + b) for a in _b85chars for b in _b85chars]
|
||||||
return _85encode(b, _b85chars, _b85chars2, pad)
|
return _85encode(b, _b85chars, _b85chars2, pad)
|
||||||
@@ -531,42 +556,28 @@ def encodebytes(s):
|
|||||||
pieces.append(binascii.b2a_base64(chunk))
|
pieces.append(binascii.b2a_base64(chunk))
|
||||||
return b"".join(pieces)
|
return b"".join(pieces)
|
||||||
|
|
||||||
def encodestring(s):
|
|
||||||
"""Legacy alias of encodebytes()."""
|
|
||||||
import warnings
|
|
||||||
warnings.warn("encodestring() is a deprecated alias since 3.1, "
|
|
||||||
"use encodebytes()",
|
|
||||||
DeprecationWarning, 2)
|
|
||||||
return encodebytes(s)
|
|
||||||
|
|
||||||
|
|
||||||
def decodebytes(s):
|
def decodebytes(s):
|
||||||
"""Decode a bytestring of base-64 data into a bytes object."""
|
"""Decode a bytestring of base-64 data into a bytes object."""
|
||||||
_input_type_check(s)
|
_input_type_check(s)
|
||||||
return binascii.a2b_base64(s)
|
return binascii.a2b_base64(s)
|
||||||
|
|
||||||
def decodestring(s):
|
|
||||||
"""Legacy alias of decodebytes()."""
|
|
||||||
import warnings
|
|
||||||
warnings.warn("decodestring() is a deprecated alias since Python 3.1, "
|
|
||||||
"use decodebytes()",
|
|
||||||
DeprecationWarning, 2)
|
|
||||||
return decodebytes(s)
|
|
||||||
|
|
||||||
|
|
||||||
# Usable as a script...
|
# Usable as a script...
|
||||||
def main():
|
def main():
|
||||||
"""Small main program"""
|
"""Small main program"""
|
||||||
import sys, getopt
|
import sys, getopt
|
||||||
|
usage = """usage: %s [-h|-d|-e|-u|-t] [file|-]
|
||||||
|
-h: print this help message and exit
|
||||||
|
-d, -u: decode
|
||||||
|
-e: encode (default)
|
||||||
|
-t: encode and decode string 'Aladdin:open sesame'"""%sys.argv[0]
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(sys.argv[1:], 'deut')
|
opts, args = getopt.getopt(sys.argv[1:], 'hdeut')
|
||||||
except getopt.error as msg:
|
except getopt.error as msg:
|
||||||
sys.stdout = sys.stderr
|
sys.stdout = sys.stderr
|
||||||
print(msg)
|
print(msg)
|
||||||
print("""usage: %s [-d|-e|-u|-t] [file|-]
|
print(usage)
|
||||||
-d, -u: decode
|
|
||||||
-e: encode (default)
|
|
||||||
-t: encode and decode string 'Aladdin:open sesame'"""%sys.argv[0])
|
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
func = encode
|
func = encode
|
||||||
for o, a in opts:
|
for o, a in opts:
|
||||||
@@ -574,6 +585,7 @@ def main():
|
|||||||
if o == '-d': func = decode
|
if o == '-d': func = decode
|
||||||
if o == '-u': func = decode
|
if o == '-u': func = decode
|
||||||
if o == '-t': test(); return
|
if o == '-t': test(); return
|
||||||
|
if o == '-h': print(usage); return
|
||||||
if args and args[0] != '-':
|
if args and args[0] != '-':
|
||||||
with open(args[0], 'rb') as f:
|
with open(args[0], 'rb') as f:
|
||||||
func(f, sys.stdout.buffer)
|
func(f, sys.stdout.buffer)
|
||||||
|
|||||||
502
Lib/binhex.py
vendored
502
Lib/binhex.py
vendored
@@ -1,502 +0,0 @@
|
|||||||
"""Macintosh binhex compression/decompression.
|
|
||||||
|
|
||||||
easy interface:
|
|
||||||
binhex(inputfilename, outputfilename)
|
|
||||||
hexbin(inputfilename, outputfilename)
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
|
||||||
# Jack Jansen, CWI, August 1995.
|
|
||||||
#
|
|
||||||
# The module is supposed to be as compatible as possible. Especially the
|
|
||||||
# easy interface should work "as expected" on any platform.
|
|
||||||
# XXXX Note: currently, textfiles appear in mac-form on all platforms.
|
|
||||||
# We seem to lack a simple character-translate in python.
|
|
||||||
# (we should probably use ISO-Latin-1 on all but the mac platform).
|
|
||||||
# XXXX The simple routines are too simple: they expect to hold the complete
|
|
||||||
# files in-core. Should be fixed.
|
|
||||||
# XXXX It would be nice to handle AppleDouble format on unix
|
|
||||||
# (for servers serving macs).
|
|
||||||
# XXXX I don't understand what happens when you get 0x90 times the same byte on
|
|
||||||
# input. The resulting code (xx 90 90) would appear to be interpreted as an
|
|
||||||
# escaped *value* of 0x90. All coders I've seen appear to ignore this nicety...
|
|
||||||
#
|
|
||||||
import binascii
|
|
||||||
import contextlib
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import struct
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn('the binhex module is deprecated', DeprecationWarning,
|
|
||||||
stacklevel=2)
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["binhex","hexbin","Error"]
|
|
||||||
|
|
||||||
class Error(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# States (what have we written)
|
|
||||||
_DID_HEADER = 0
|
|
||||||
_DID_DATA = 1
|
|
||||||
|
|
||||||
# Various constants
|
|
||||||
REASONABLY_LARGE = 32768 # Minimal amount we pass the rle-coder
|
|
||||||
LINELEN = 64
|
|
||||||
RUNCHAR = b"\x90"
|
|
||||||
|
|
||||||
#
|
|
||||||
# This code is no longer byte-order dependent
|
|
||||||
|
|
||||||
|
|
||||||
class FInfo:
|
|
||||||
def __init__(self):
|
|
||||||
self.Type = '????'
|
|
||||||
self.Creator = '????'
|
|
||||||
self.Flags = 0
|
|
||||||
|
|
||||||
def getfileinfo(name):
|
|
||||||
finfo = FInfo()
|
|
||||||
with io.open(name, 'rb') as fp:
|
|
||||||
# Quick check for textfile
|
|
||||||
data = fp.read(512)
|
|
||||||
if 0 not in data:
|
|
||||||
finfo.Type = 'TEXT'
|
|
||||||
fp.seek(0, 2)
|
|
||||||
dsize = fp.tell()
|
|
||||||
dir, file = os.path.split(name)
|
|
||||||
file = file.replace(':', '-', 1)
|
|
||||||
return file, finfo, dsize, 0
|
|
||||||
|
|
||||||
class openrsrc:
|
|
||||||
def __init__(self, *args):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def read(self, *args):
|
|
||||||
return b''
|
|
||||||
|
|
||||||
def write(self, *args):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# DeprecationWarning is already emitted on "import binhex". There is no need
|
|
||||||
# to repeat the warning at each call to deprecated binascii functions.
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def _ignore_deprecation_warning():
|
|
||||||
with warnings.catch_warnings():
|
|
||||||
warnings.filterwarnings('ignore', '', DeprecationWarning)
|
|
||||||
yield
|
|
||||||
|
|
||||||
|
|
||||||
class _Hqxcoderengine:
|
|
||||||
"""Write data to the coder in 3-byte chunks"""
|
|
||||||
|
|
||||||
def __init__(self, ofp):
|
|
||||||
self.ofp = ofp
|
|
||||||
self.data = b''
|
|
||||||
self.hqxdata = b''
|
|
||||||
self.linelen = LINELEN - 1
|
|
||||||
|
|
||||||
def write(self, data):
|
|
||||||
self.data = self.data + data
|
|
||||||
datalen = len(self.data)
|
|
||||||
todo = (datalen // 3) * 3
|
|
||||||
data = self.data[:todo]
|
|
||||||
self.data = self.data[todo:]
|
|
||||||
if not data:
|
|
||||||
return
|
|
||||||
with _ignore_deprecation_warning():
|
|
||||||
self.hqxdata = self.hqxdata + binascii.b2a_hqx(data)
|
|
||||||
self._flush(0)
|
|
||||||
|
|
||||||
def _flush(self, force):
|
|
||||||
first = 0
|
|
||||||
while first <= len(self.hqxdata) - self.linelen:
|
|
||||||
last = first + self.linelen
|
|
||||||
self.ofp.write(self.hqxdata[first:last] + b'\r')
|
|
||||||
self.linelen = LINELEN
|
|
||||||
first = last
|
|
||||||
self.hqxdata = self.hqxdata[first:]
|
|
||||||
if force:
|
|
||||||
self.ofp.write(self.hqxdata + b':\r')
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
if self.data:
|
|
||||||
with _ignore_deprecation_warning():
|
|
||||||
self.hqxdata = self.hqxdata + binascii.b2a_hqx(self.data)
|
|
||||||
self._flush(1)
|
|
||||||
self.ofp.close()
|
|
||||||
del self.ofp
|
|
||||||
|
|
||||||
class _Rlecoderengine:
|
|
||||||
"""Write data to the RLE-coder in suitably large chunks"""
|
|
||||||
|
|
||||||
def __init__(self, ofp):
|
|
||||||
self.ofp = ofp
|
|
||||||
self.data = b''
|
|
||||||
|
|
||||||
def write(self, data):
|
|
||||||
self.data = self.data + data
|
|
||||||
if len(self.data) < REASONABLY_LARGE:
|
|
||||||
return
|
|
||||||
with _ignore_deprecation_warning():
|
|
||||||
rledata = binascii.rlecode_hqx(self.data)
|
|
||||||
self.ofp.write(rledata)
|
|
||||||
self.data = b''
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
if self.data:
|
|
||||||
with _ignore_deprecation_warning():
|
|
||||||
rledata = binascii.rlecode_hqx(self.data)
|
|
||||||
self.ofp.write(rledata)
|
|
||||||
self.ofp.close()
|
|
||||||
del self.ofp
|
|
||||||
|
|
||||||
class BinHex:
|
|
||||||
def __init__(self, name_finfo_dlen_rlen, ofp):
|
|
||||||
name, finfo, dlen, rlen = name_finfo_dlen_rlen
|
|
||||||
close_on_error = False
|
|
||||||
if isinstance(ofp, str):
|
|
||||||
ofname = ofp
|
|
||||||
ofp = io.open(ofname, 'wb')
|
|
||||||
close_on_error = True
|
|
||||||
try:
|
|
||||||
ofp.write(b'(This file must be converted with BinHex 4.0)\r\r:')
|
|
||||||
hqxer = _Hqxcoderengine(ofp)
|
|
||||||
self.ofp = _Rlecoderengine(hqxer)
|
|
||||||
self.crc = 0
|
|
||||||
if finfo is None:
|
|
||||||
finfo = FInfo()
|
|
||||||
self.dlen = dlen
|
|
||||||
self.rlen = rlen
|
|
||||||
self._writeinfo(name, finfo)
|
|
||||||
self.state = _DID_HEADER
|
|
||||||
except:
|
|
||||||
if close_on_error:
|
|
||||||
ofp.close()
|
|
||||||
raise
|
|
||||||
|
|
||||||
def _writeinfo(self, name, finfo):
|
|
||||||
nl = len(name)
|
|
||||||
if nl > 63:
|
|
||||||
raise Error('Filename too long')
|
|
||||||
d = bytes([nl]) + name.encode("latin-1") + b'\0'
|
|
||||||
tp, cr = finfo.Type, finfo.Creator
|
|
||||||
if isinstance(tp, str):
|
|
||||||
tp = tp.encode("latin-1")
|
|
||||||
if isinstance(cr, str):
|
|
||||||
cr = cr.encode("latin-1")
|
|
||||||
d2 = tp + cr
|
|
||||||
|
|
||||||
# Force all structs to be packed with big-endian
|
|
||||||
d3 = struct.pack('>h', finfo.Flags)
|
|
||||||
d4 = struct.pack('>ii', self.dlen, self.rlen)
|
|
||||||
info = d + d2 + d3 + d4
|
|
||||||
self._write(info)
|
|
||||||
self._writecrc()
|
|
||||||
|
|
||||||
def _write(self, data):
|
|
||||||
self.crc = binascii.crc_hqx(data, self.crc)
|
|
||||||
self.ofp.write(data)
|
|
||||||
|
|
||||||
def _writecrc(self):
|
|
||||||
# XXXX Should this be here??
|
|
||||||
# self.crc = binascii.crc_hqx('\0\0', self.crc)
|
|
||||||
if self.crc < 0:
|
|
||||||
fmt = '>h'
|
|
||||||
else:
|
|
||||||
fmt = '>H'
|
|
||||||
self.ofp.write(struct.pack(fmt, self.crc))
|
|
||||||
self.crc = 0
|
|
||||||
|
|
||||||
def write(self, data):
|
|
||||||
if self.state != _DID_HEADER:
|
|
||||||
raise Error('Writing data at the wrong time')
|
|
||||||
self.dlen = self.dlen - len(data)
|
|
||||||
self._write(data)
|
|
||||||
|
|
||||||
def close_data(self):
|
|
||||||
if self.dlen != 0:
|
|
||||||
raise Error('Incorrect data size, diff=%r' % (self.rlen,))
|
|
||||||
self._writecrc()
|
|
||||||
self.state = _DID_DATA
|
|
||||||
|
|
||||||
def write_rsrc(self, data):
|
|
||||||
if self.state < _DID_DATA:
|
|
||||||
self.close_data()
|
|
||||||
if self.state != _DID_DATA:
|
|
||||||
raise Error('Writing resource data at the wrong time')
|
|
||||||
self.rlen = self.rlen - len(data)
|
|
||||||
self._write(data)
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
if self.state is None:
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
if self.state < _DID_DATA:
|
|
||||||
self.close_data()
|
|
||||||
if self.state != _DID_DATA:
|
|
||||||
raise Error('Close at the wrong time')
|
|
||||||
if self.rlen != 0:
|
|
||||||
raise Error("Incorrect resource-datasize, diff=%r" % (self.rlen,))
|
|
||||||
self._writecrc()
|
|
||||||
finally:
|
|
||||||
self.state = None
|
|
||||||
ofp = self.ofp
|
|
||||||
del self.ofp
|
|
||||||
ofp.close()
|
|
||||||
|
|
||||||
def binhex(inp, out):
|
|
||||||
"""binhex(infilename, outfilename): create binhex-encoded copy of a file"""
|
|
||||||
finfo = getfileinfo(inp)
|
|
||||||
ofp = BinHex(finfo, out)
|
|
||||||
|
|
||||||
with io.open(inp, 'rb') as ifp:
|
|
||||||
# XXXX Do textfile translation on non-mac systems
|
|
||||||
while True:
|
|
||||||
d = ifp.read(128000)
|
|
||||||
if not d: break
|
|
||||||
ofp.write(d)
|
|
||||||
ofp.close_data()
|
|
||||||
|
|
||||||
ifp = openrsrc(inp, 'rb')
|
|
||||||
while True:
|
|
||||||
d = ifp.read(128000)
|
|
||||||
if not d: break
|
|
||||||
ofp.write_rsrc(d)
|
|
||||||
ofp.close()
|
|
||||||
ifp.close()
|
|
||||||
|
|
||||||
class _Hqxdecoderengine:
|
|
||||||
"""Read data via the decoder in 4-byte chunks"""
|
|
||||||
|
|
||||||
def __init__(self, ifp):
|
|
||||||
self.ifp = ifp
|
|
||||||
self.eof = 0
|
|
||||||
|
|
||||||
def read(self, totalwtd):
|
|
||||||
"""Read at least wtd bytes (or until EOF)"""
|
|
||||||
decdata = b''
|
|
||||||
wtd = totalwtd
|
|
||||||
#
|
|
||||||
# The loop here is convoluted, since we don't really now how
|
|
||||||
# much to decode: there may be newlines in the incoming data.
|
|
||||||
while wtd > 0:
|
|
||||||
if self.eof: return decdata
|
|
||||||
wtd = ((wtd + 2) // 3) * 4
|
|
||||||
data = self.ifp.read(wtd)
|
|
||||||
#
|
|
||||||
# Next problem: there may not be a complete number of
|
|
||||||
# bytes in what we pass to a2b. Solve by yet another
|
|
||||||
# loop.
|
|
||||||
#
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
with _ignore_deprecation_warning():
|
|
||||||
decdatacur, self.eof = binascii.a2b_hqx(data)
|
|
||||||
break
|
|
||||||
except binascii.Incomplete:
|
|
||||||
pass
|
|
||||||
newdata = self.ifp.read(1)
|
|
||||||
if not newdata:
|
|
||||||
raise Error('Premature EOF on binhex file')
|
|
||||||
data = data + newdata
|
|
||||||
decdata = decdata + decdatacur
|
|
||||||
wtd = totalwtd - len(decdata)
|
|
||||||
if not decdata and not self.eof:
|
|
||||||
raise Error('Premature EOF on binhex file')
|
|
||||||
return decdata
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
self.ifp.close()
|
|
||||||
|
|
||||||
class _Rledecoderengine:
|
|
||||||
"""Read data via the RLE-coder"""
|
|
||||||
|
|
||||||
def __init__(self, ifp):
|
|
||||||
self.ifp = ifp
|
|
||||||
self.pre_buffer = b''
|
|
||||||
self.post_buffer = b''
|
|
||||||
self.eof = 0
|
|
||||||
|
|
||||||
def read(self, wtd):
|
|
||||||
if wtd > len(self.post_buffer):
|
|
||||||
self._fill(wtd - len(self.post_buffer))
|
|
||||||
rv = self.post_buffer[:wtd]
|
|
||||||
self.post_buffer = self.post_buffer[wtd:]
|
|
||||||
return rv
|
|
||||||
|
|
||||||
def _fill(self, wtd):
|
|
||||||
self.pre_buffer = self.pre_buffer + self.ifp.read(wtd + 4)
|
|
||||||
if self.ifp.eof:
|
|
||||||
with _ignore_deprecation_warning():
|
|
||||||
self.post_buffer = self.post_buffer + \
|
|
||||||
binascii.rledecode_hqx(self.pre_buffer)
|
|
||||||
self.pre_buffer = b''
|
|
||||||
return
|
|
||||||
|
|
||||||
#
|
|
||||||
# Obfuscated code ahead. We have to take care that we don't
|
|
||||||
# end up with an orphaned RUNCHAR later on. So, we keep a couple
|
|
||||||
# of bytes in the buffer, depending on what the end of
|
|
||||||
# the buffer looks like:
|
|
||||||
# '\220\0\220' - Keep 3 bytes: repeated \220 (escaped as \220\0)
|
|
||||||
# '?\220' - Keep 2 bytes: repeated something-else
|
|
||||||
# '\220\0' - Escaped \220: Keep 2 bytes.
|
|
||||||
# '?\220?' - Complete repeat sequence: decode all
|
|
||||||
# otherwise: keep 1 byte.
|
|
||||||
#
|
|
||||||
mark = len(self.pre_buffer)
|
|
||||||
if self.pre_buffer[-3:] == RUNCHAR + b'\0' + RUNCHAR:
|
|
||||||
mark = mark - 3
|
|
||||||
elif self.pre_buffer[-1:] == RUNCHAR:
|
|
||||||
mark = mark - 2
|
|
||||||
elif self.pre_buffer[-2:] == RUNCHAR + b'\0':
|
|
||||||
mark = mark - 2
|
|
||||||
elif self.pre_buffer[-2:-1] == RUNCHAR:
|
|
||||||
pass # Decode all
|
|
||||||
else:
|
|
||||||
mark = mark - 1
|
|
||||||
|
|
||||||
with _ignore_deprecation_warning():
|
|
||||||
self.post_buffer = self.post_buffer + \
|
|
||||||
binascii.rledecode_hqx(self.pre_buffer[:mark])
|
|
||||||
self.pre_buffer = self.pre_buffer[mark:]
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
self.ifp.close()
|
|
||||||
|
|
||||||
class HexBin:
|
|
||||||
def __init__(self, ifp):
|
|
||||||
if isinstance(ifp, str):
|
|
||||||
ifp = io.open(ifp, 'rb')
|
|
||||||
#
|
|
||||||
# Find initial colon.
|
|
||||||
#
|
|
||||||
while True:
|
|
||||||
ch = ifp.read(1)
|
|
||||||
if not ch:
|
|
||||||
raise Error("No binhex data found")
|
|
||||||
# Cater for \r\n terminated lines (which show up as \n\r, hence
|
|
||||||
# all lines start with \r)
|
|
||||||
if ch == b'\r':
|
|
||||||
continue
|
|
||||||
if ch == b':':
|
|
||||||
break
|
|
||||||
|
|
||||||
hqxifp = _Hqxdecoderengine(ifp)
|
|
||||||
self.ifp = _Rledecoderengine(hqxifp)
|
|
||||||
self.crc = 0
|
|
||||||
self._readheader()
|
|
||||||
|
|
||||||
def _read(self, len):
|
|
||||||
data = self.ifp.read(len)
|
|
||||||
self.crc = binascii.crc_hqx(data, self.crc)
|
|
||||||
return data
|
|
||||||
|
|
||||||
def _checkcrc(self):
|
|
||||||
filecrc = struct.unpack('>h', self.ifp.read(2))[0] & 0xffff
|
|
||||||
#self.crc = binascii.crc_hqx('\0\0', self.crc)
|
|
||||||
# XXXX Is this needed??
|
|
||||||
self.crc = self.crc & 0xffff
|
|
||||||
if filecrc != self.crc:
|
|
||||||
raise Error('CRC error, computed %x, read %x'
|
|
||||||
% (self.crc, filecrc))
|
|
||||||
self.crc = 0
|
|
||||||
|
|
||||||
def _readheader(self):
|
|
||||||
len = self._read(1)
|
|
||||||
fname = self._read(ord(len))
|
|
||||||
rest = self._read(1 + 4 + 4 + 2 + 4 + 4)
|
|
||||||
self._checkcrc()
|
|
||||||
|
|
||||||
type = rest[1:5]
|
|
||||||
creator = rest[5:9]
|
|
||||||
flags = struct.unpack('>h', rest[9:11])[0]
|
|
||||||
self.dlen = struct.unpack('>l', rest[11:15])[0]
|
|
||||||
self.rlen = struct.unpack('>l', rest[15:19])[0]
|
|
||||||
|
|
||||||
self.FName = fname
|
|
||||||
self.FInfo = FInfo()
|
|
||||||
self.FInfo.Creator = creator
|
|
||||||
self.FInfo.Type = type
|
|
||||||
self.FInfo.Flags = flags
|
|
||||||
|
|
||||||
self.state = _DID_HEADER
|
|
||||||
|
|
||||||
def read(self, *n):
|
|
||||||
if self.state != _DID_HEADER:
|
|
||||||
raise Error('Read data at wrong time')
|
|
||||||
if n:
|
|
||||||
n = n[0]
|
|
||||||
n = min(n, self.dlen)
|
|
||||||
else:
|
|
||||||
n = self.dlen
|
|
||||||
rv = b''
|
|
||||||
while len(rv) < n:
|
|
||||||
rv = rv + self._read(n-len(rv))
|
|
||||||
self.dlen = self.dlen - n
|
|
||||||
return rv
|
|
||||||
|
|
||||||
def close_data(self):
|
|
||||||
if self.state != _DID_HEADER:
|
|
||||||
raise Error('close_data at wrong time')
|
|
||||||
if self.dlen:
|
|
||||||
dummy = self._read(self.dlen)
|
|
||||||
self._checkcrc()
|
|
||||||
self.state = _DID_DATA
|
|
||||||
|
|
||||||
def read_rsrc(self, *n):
|
|
||||||
if self.state == _DID_HEADER:
|
|
||||||
self.close_data()
|
|
||||||
if self.state != _DID_DATA:
|
|
||||||
raise Error('Read resource data at wrong time')
|
|
||||||
if n:
|
|
||||||
n = n[0]
|
|
||||||
n = min(n, self.rlen)
|
|
||||||
else:
|
|
||||||
n = self.rlen
|
|
||||||
self.rlen = self.rlen - n
|
|
||||||
return self._read(n)
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
if self.state is None:
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
if self.rlen:
|
|
||||||
dummy = self.read_rsrc(self.rlen)
|
|
||||||
self._checkcrc()
|
|
||||||
finally:
|
|
||||||
self.state = None
|
|
||||||
self.ifp.close()
|
|
||||||
|
|
||||||
def hexbin(inp, out):
|
|
||||||
"""hexbin(infilename, outfilename) - Decode binhexed file"""
|
|
||||||
ifp = HexBin(inp)
|
|
||||||
finfo = ifp.FInfo
|
|
||||||
if not out:
|
|
||||||
out = ifp.FName
|
|
||||||
|
|
||||||
with io.open(out, 'wb') as ofp:
|
|
||||||
# XXXX Do translation on non-mac systems
|
|
||||||
while True:
|
|
||||||
d = ifp.read(128000)
|
|
||||||
if not d: break
|
|
||||||
ofp.write(d)
|
|
||||||
ifp.close_data()
|
|
||||||
|
|
||||||
d = ifp.read_rsrc(128000)
|
|
||||||
if d:
|
|
||||||
ofp = openrsrc(out, 'wb')
|
|
||||||
ofp.write(d)
|
|
||||||
while True:
|
|
||||||
d = ifp.read_rsrc(128000)
|
|
||||||
if not d: break
|
|
||||||
ofp.write(d)
|
|
||||||
ofp.close()
|
|
||||||
|
|
||||||
ifp.close()
|
|
||||||
2
Lib/bisect.py
vendored
2
Lib/bisect.py
vendored
@@ -107,4 +107,4 @@ except ImportError:
|
|||||||
|
|
||||||
# Create aliases
|
# Create aliases
|
||||||
bisect = bisect_right
|
bisect = bisect_right
|
||||||
insort = insort_right
|
insort = insort_right
|
||||||
|
|||||||
52
Lib/calendar.py
vendored
52
Lib/calendar.py
vendored
@@ -15,7 +15,9 @@ __all__ = ["IllegalMonthError", "IllegalWeekdayError", "setfirstweekday",
|
|||||||
"monthcalendar", "prmonth", "month", "prcal", "calendar",
|
"monthcalendar", "prmonth", "month", "prcal", "calendar",
|
||||||
"timegm", "month_name", "month_abbr", "day_name", "day_abbr",
|
"timegm", "month_name", "month_abbr", "day_name", "day_abbr",
|
||||||
"Calendar", "TextCalendar", "HTMLCalendar", "LocaleTextCalendar",
|
"Calendar", "TextCalendar", "HTMLCalendar", "LocaleTextCalendar",
|
||||||
"LocaleHTMLCalendar", "weekheader"]
|
"LocaleHTMLCalendar", "weekheader",
|
||||||
|
"MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY",
|
||||||
|
"SATURDAY", "SUNDAY"]
|
||||||
|
|
||||||
# Exception raised for bad input (with string parameter for details)
|
# Exception raised for bad input (with string parameter for details)
|
||||||
error = ValueError
|
error = ValueError
|
||||||
@@ -546,71 +548,67 @@ class HTMLCalendar(Calendar):
|
|||||||
class different_locale:
|
class different_locale:
|
||||||
def __init__(self, locale):
|
def __init__(self, locale):
|
||||||
self.locale = locale
|
self.locale = locale
|
||||||
|
self.oldlocale = None
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self.oldlocale = _locale.getlocale(_locale.LC_TIME)
|
self.oldlocale = _locale.setlocale(_locale.LC_TIME, None)
|
||||||
_locale.setlocale(_locale.LC_TIME, self.locale)
|
_locale.setlocale(_locale.LC_TIME, self.locale)
|
||||||
|
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
|
if self.oldlocale is None:
|
||||||
|
return
|
||||||
_locale.setlocale(_locale.LC_TIME, self.oldlocale)
|
_locale.setlocale(_locale.LC_TIME, self.oldlocale)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_default_locale():
|
||||||
|
locale = _locale.setlocale(_locale.LC_TIME, None)
|
||||||
|
if locale == "C":
|
||||||
|
with different_locale(""):
|
||||||
|
# The LC_TIME locale does not seem to be configured:
|
||||||
|
# get the user preferred locale.
|
||||||
|
locale = _locale.setlocale(_locale.LC_TIME, None)
|
||||||
|
return locale
|
||||||
|
|
||||||
|
|
||||||
class LocaleTextCalendar(TextCalendar):
|
class LocaleTextCalendar(TextCalendar):
|
||||||
"""
|
"""
|
||||||
This class can be passed a locale name in the constructor and will return
|
This class can be passed a locale name in the constructor and will return
|
||||||
month and weekday names in the specified locale. If this locale includes
|
month and weekday names in the specified locale.
|
||||||
an encoding all strings containing month and weekday names will be returned
|
|
||||||
as unicode.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, firstweekday=0, locale=None):
|
def __init__(self, firstweekday=0, locale=None):
|
||||||
TextCalendar.__init__(self, firstweekday)
|
TextCalendar.__init__(self, firstweekday)
|
||||||
if locale is None:
|
if locale is None:
|
||||||
locale = _locale.getdefaultlocale()
|
locale = _get_default_locale()
|
||||||
self.locale = locale
|
self.locale = locale
|
||||||
|
|
||||||
def formatweekday(self, day, width):
|
def formatweekday(self, day, width):
|
||||||
with different_locale(self.locale):
|
with different_locale(self.locale):
|
||||||
if width >= 9:
|
return super().formatweekday(day, width)
|
||||||
names = day_name
|
|
||||||
else:
|
|
||||||
names = day_abbr
|
|
||||||
name = names[day]
|
|
||||||
return name[:width].center(width)
|
|
||||||
|
|
||||||
def formatmonthname(self, theyear, themonth, width, withyear=True):
|
def formatmonthname(self, theyear, themonth, width, withyear=True):
|
||||||
with different_locale(self.locale):
|
with different_locale(self.locale):
|
||||||
s = month_name[themonth]
|
return super().formatmonthname(theyear, themonth, width, withyear)
|
||||||
if withyear:
|
|
||||||
s = "%s %r" % (s, theyear)
|
|
||||||
return s.center(width)
|
|
||||||
|
|
||||||
|
|
||||||
class LocaleHTMLCalendar(HTMLCalendar):
|
class LocaleHTMLCalendar(HTMLCalendar):
|
||||||
"""
|
"""
|
||||||
This class can be passed a locale name in the constructor and will return
|
This class can be passed a locale name in the constructor and will return
|
||||||
month and weekday names in the specified locale. If this locale includes
|
month and weekday names in the specified locale.
|
||||||
an encoding all strings containing month and weekday names will be returned
|
|
||||||
as unicode.
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, firstweekday=0, locale=None):
|
def __init__(self, firstweekday=0, locale=None):
|
||||||
HTMLCalendar.__init__(self, firstweekday)
|
HTMLCalendar.__init__(self, firstweekday)
|
||||||
if locale is None:
|
if locale is None:
|
||||||
locale = _locale.getdefaultlocale()
|
locale = _get_default_locale()
|
||||||
self.locale = locale
|
self.locale = locale
|
||||||
|
|
||||||
def formatweekday(self, day):
|
def formatweekday(self, day):
|
||||||
with different_locale(self.locale):
|
with different_locale(self.locale):
|
||||||
s = day_abbr[day]
|
return super().formatweekday(day)
|
||||||
return '<th class="%s">%s</th>' % (self.cssclasses[day], s)
|
|
||||||
|
|
||||||
def formatmonthname(self, theyear, themonth, withyear=True):
|
def formatmonthname(self, theyear, themonth, withyear=True):
|
||||||
with different_locale(self.locale):
|
with different_locale(self.locale):
|
||||||
s = month_name[themonth]
|
return super().formatmonthname(theyear, themonth, withyear)
|
||||||
if withyear:
|
|
||||||
s = '%s %s' % (s, theyear)
|
|
||||||
return '<tr><th colspan="7" class="month">%s</th></tr>' % s
|
|
||||||
|
|
||||||
|
|
||||||
# Support for old module level interface
|
# Support for old module level interface
|
||||||
c = TextCalendar()
|
c = TextCalendar()
|
||||||
|
|||||||
46
Lib/cgi.py
vendored
46
Lib/cgi.py
vendored
@@ -13,6 +13,11 @@
|
|||||||
|
|
||||||
This module defines a number of utilities for use by CGI scripts
|
This module defines a number of utilities for use by CGI scripts
|
||||||
written in Python.
|
written in Python.
|
||||||
|
|
||||||
|
The global variable maxlen can be set to an integer indicating the maximum size
|
||||||
|
of a POST request. POST requests larger than this size will result in a
|
||||||
|
ValueError being raised during parsing. The default value of this variable is 0,
|
||||||
|
meaning the request size is unlimited.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# History
|
# History
|
||||||
@@ -41,12 +46,16 @@ from email.message import Message
|
|||||||
import html
|
import html
|
||||||
import locale
|
import locale
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import warnings
|
||||||
|
|
||||||
__all__ = ["MiniFieldStorage", "FieldStorage", "parse", "parse_multipart",
|
__all__ = ["MiniFieldStorage", "FieldStorage", "parse", "parse_multipart",
|
||||||
"parse_header", "test", "print_exception", "print_environ",
|
"parse_header", "test", "print_exception", "print_environ",
|
||||||
"print_form", "print_directory", "print_arguments",
|
"print_form", "print_directory", "print_arguments",
|
||||||
"print_environ_usage"]
|
"print_environ_usage"]
|
||||||
|
|
||||||
|
|
||||||
|
warnings._deprecated(__name__, remove=(3,13))
|
||||||
|
|
||||||
# Logging support
|
# Logging support
|
||||||
# ===============
|
# ===============
|
||||||
|
|
||||||
@@ -77,9 +86,11 @@ def initlog(*allargs):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
global log, logfile, logfp
|
global log, logfile, logfp
|
||||||
|
warnings.warn("cgi.log() is deprecated as of 3.10. Use logging instead",
|
||||||
|
DeprecationWarning, stacklevel=2)
|
||||||
if logfile and not logfp:
|
if logfile and not logfp:
|
||||||
try:
|
try:
|
||||||
logfp = open(logfile, "a")
|
logfp = open(logfile, "a", encoding="locale")
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
if not logfp:
|
if not logfp:
|
||||||
@@ -115,7 +126,8 @@ log = initlog # The current logging function
|
|||||||
# 0 ==> unlimited input
|
# 0 ==> unlimited input
|
||||||
maxlen = 0
|
maxlen = 0
|
||||||
|
|
||||||
def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
|
def parse(fp=None, environ=os.environ, keep_blank_values=0,
|
||||||
|
strict_parsing=0, separator='&'):
|
||||||
"""Parse a query in the environment or from a file (default stdin)
|
"""Parse a query in the environment or from a file (default stdin)
|
||||||
|
|
||||||
Arguments, all optional:
|
Arguments, all optional:
|
||||||
@@ -134,6 +146,9 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
|
|||||||
strict_parsing: flag indicating what to do with parsing errors.
|
strict_parsing: flag indicating what to do with parsing errors.
|
||||||
If false (the default), errors are silently ignored.
|
If false (the default), errors are silently ignored.
|
||||||
If true, errors raise a ValueError exception.
|
If true, errors raise a ValueError exception.
|
||||||
|
|
||||||
|
separator: str. The symbol to use for separating the query arguments.
|
||||||
|
Defaults to &.
|
||||||
"""
|
"""
|
||||||
if fp is None:
|
if fp is None:
|
||||||
fp = sys.stdin
|
fp = sys.stdin
|
||||||
@@ -154,7 +169,7 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
|
|||||||
if environ['REQUEST_METHOD'] == 'POST':
|
if environ['REQUEST_METHOD'] == 'POST':
|
||||||
ctype, pdict = parse_header(environ['CONTENT_TYPE'])
|
ctype, pdict = parse_header(environ['CONTENT_TYPE'])
|
||||||
if ctype == 'multipart/form-data':
|
if ctype == 'multipart/form-data':
|
||||||
return parse_multipart(fp, pdict)
|
return parse_multipart(fp, pdict, separator=separator)
|
||||||
elif ctype == 'application/x-www-form-urlencoded':
|
elif ctype == 'application/x-www-form-urlencoded':
|
||||||
clength = int(environ['CONTENT_LENGTH'])
|
clength = int(environ['CONTENT_LENGTH'])
|
||||||
if maxlen and clength > maxlen:
|
if maxlen and clength > maxlen:
|
||||||
@@ -178,10 +193,10 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
|
|||||||
qs = ""
|
qs = ""
|
||||||
environ['QUERY_STRING'] = qs # XXX Shouldn't, really
|
environ['QUERY_STRING'] = qs # XXX Shouldn't, really
|
||||||
return urllib.parse.parse_qs(qs, keep_blank_values, strict_parsing,
|
return urllib.parse.parse_qs(qs, keep_blank_values, strict_parsing,
|
||||||
encoding=encoding)
|
encoding=encoding, separator=separator)
|
||||||
|
|
||||||
|
|
||||||
def parse_multipart(fp, pdict, encoding="utf-8", errors="replace"):
|
def parse_multipart(fp, pdict, encoding="utf-8", errors="replace", separator='&'):
|
||||||
"""Parse multipart input.
|
"""Parse multipart input.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
@@ -194,15 +209,18 @@ def parse_multipart(fp, pdict, encoding="utf-8", errors="replace"):
|
|||||||
value is a list of values for that field. For non-file fields, the value
|
value is a list of values for that field. For non-file fields, the value
|
||||||
is a list of strings.
|
is a list of strings.
|
||||||
"""
|
"""
|
||||||
# RFC 2026, Section 5.1 : The "multipart" boundary delimiters are always
|
# RFC 2046, Section 5.1 : The "multipart" boundary delimiters are always
|
||||||
# represented as 7bit US-ASCII.
|
# represented as 7bit US-ASCII.
|
||||||
boundary = pdict['boundary'].decode('ascii')
|
boundary = pdict['boundary'].decode('ascii')
|
||||||
ctype = "multipart/form-data; boundary={}".format(boundary)
|
ctype = "multipart/form-data; boundary={}".format(boundary)
|
||||||
headers = Message()
|
headers = Message()
|
||||||
headers.set_type(ctype)
|
headers.set_type(ctype)
|
||||||
headers['Content-Length'] = pdict['CONTENT-LENGTH']
|
try:
|
||||||
|
headers['Content-Length'] = pdict['CONTENT-LENGTH']
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
fs = FieldStorage(fp, headers=headers, encoding=encoding, errors=errors,
|
fs = FieldStorage(fp, headers=headers, encoding=encoding, errors=errors,
|
||||||
environ={'REQUEST_METHOD': 'POST'})
|
environ={'REQUEST_METHOD': 'POST'}, separator=separator)
|
||||||
return {k: fs.getlist(k) for k in fs}
|
return {k: fs.getlist(k) for k in fs}
|
||||||
|
|
||||||
def _parseparam(s):
|
def _parseparam(s):
|
||||||
@@ -312,7 +330,7 @@ class FieldStorage:
|
|||||||
def __init__(self, fp=None, headers=None, outerboundary=b'',
|
def __init__(self, fp=None, headers=None, outerboundary=b'',
|
||||||
environ=os.environ, keep_blank_values=0, strict_parsing=0,
|
environ=os.environ, keep_blank_values=0, strict_parsing=0,
|
||||||
limit=None, encoding='utf-8', errors='replace',
|
limit=None, encoding='utf-8', errors='replace',
|
||||||
max_num_fields=None):
|
max_num_fields=None, separator='&'):
|
||||||
"""Constructor. Read multipart/* until last part.
|
"""Constructor. Read multipart/* until last part.
|
||||||
|
|
||||||
Arguments, all optional:
|
Arguments, all optional:
|
||||||
@@ -360,6 +378,7 @@ class FieldStorage:
|
|||||||
self.keep_blank_values = keep_blank_values
|
self.keep_blank_values = keep_blank_values
|
||||||
self.strict_parsing = strict_parsing
|
self.strict_parsing = strict_parsing
|
||||||
self.max_num_fields = max_num_fields
|
self.max_num_fields = max_num_fields
|
||||||
|
self.separator = separator
|
||||||
if 'REQUEST_METHOD' in environ:
|
if 'REQUEST_METHOD' in environ:
|
||||||
method = environ['REQUEST_METHOD'].upper()
|
method = environ['REQUEST_METHOD'].upper()
|
||||||
self.qs_on_post = None
|
self.qs_on_post = None
|
||||||
@@ -586,7 +605,7 @@ class FieldStorage:
|
|||||||
query = urllib.parse.parse_qsl(
|
query = urllib.parse.parse_qsl(
|
||||||
qs, self.keep_blank_values, self.strict_parsing,
|
qs, self.keep_blank_values, self.strict_parsing,
|
||||||
encoding=self.encoding, errors=self.errors,
|
encoding=self.encoding, errors=self.errors,
|
||||||
max_num_fields=self.max_num_fields)
|
max_num_fields=self.max_num_fields, separator=self.separator)
|
||||||
self.list = [MiniFieldStorage(key, value) for key, value in query]
|
self.list = [MiniFieldStorage(key, value) for key, value in query]
|
||||||
self.skip_lines()
|
self.skip_lines()
|
||||||
|
|
||||||
@@ -602,7 +621,7 @@ class FieldStorage:
|
|||||||
query = urllib.parse.parse_qsl(
|
query = urllib.parse.parse_qsl(
|
||||||
self.qs_on_post, self.keep_blank_values, self.strict_parsing,
|
self.qs_on_post, self.keep_blank_values, self.strict_parsing,
|
||||||
encoding=self.encoding, errors=self.errors,
|
encoding=self.encoding, errors=self.errors,
|
||||||
max_num_fields=self.max_num_fields)
|
max_num_fields=self.max_num_fields, separator=self.separator)
|
||||||
self.list.extend(MiniFieldStorage(key, value) for key, value in query)
|
self.list.extend(MiniFieldStorage(key, value) for key, value in query)
|
||||||
|
|
||||||
klass = self.FieldStorageClass or self.__class__
|
klass = self.FieldStorageClass or self.__class__
|
||||||
@@ -646,7 +665,7 @@ class FieldStorage:
|
|||||||
else self.limit - self.bytes_read
|
else self.limit - self.bytes_read
|
||||||
part = klass(self.fp, headers, ib, environ, keep_blank_values,
|
part = klass(self.fp, headers, ib, environ, keep_blank_values,
|
||||||
strict_parsing, limit,
|
strict_parsing, limit,
|
||||||
self.encoding, self.errors, max_num_fields)
|
self.encoding, self.errors, max_num_fields, self.separator)
|
||||||
|
|
||||||
if max_num_fields is not None:
|
if max_num_fields is not None:
|
||||||
max_num_fields -= 1
|
max_num_fields -= 1
|
||||||
@@ -736,7 +755,8 @@ class FieldStorage:
|
|||||||
last_line_lfend = True
|
last_line_lfend = True
|
||||||
_read = 0
|
_read = 0
|
||||||
while 1:
|
while 1:
|
||||||
if self.limit is not None and _read >= self.limit:
|
|
||||||
|
if self.limit is not None and 0 <= self.limit <= _read:
|
||||||
break
|
break
|
||||||
line = self.fp.readline(1<<16) # bytes
|
line = self.fp.readline(1<<16) # bytes
|
||||||
self.bytes_read += len(line)
|
self.bytes_read += len(line)
|
||||||
|
|||||||
23
Lib/cgitb.py
vendored
23
Lib/cgitb.py
vendored
@@ -31,6 +31,11 @@ import tempfile
|
|||||||
import time
|
import time
|
||||||
import tokenize
|
import tokenize
|
||||||
import traceback
|
import traceback
|
||||||
|
import warnings
|
||||||
|
from html import escape as html_escape
|
||||||
|
|
||||||
|
warnings._deprecated(__name__, remove=(3, 13))
|
||||||
|
|
||||||
|
|
||||||
def reset():
|
def reset():
|
||||||
"""Return a string that resets the CGI and browser to a known state."""
|
"""Return a string that resets the CGI and browser to a known state."""
|
||||||
@@ -105,10 +110,16 @@ def html(einfo, context=5):
|
|||||||
etype = etype.__name__
|
etype = etype.__name__
|
||||||
pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
|
pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
|
||||||
date = time.ctime(time.time())
|
date = time.ctime(time.time())
|
||||||
head = '<body bgcolor="#f0f0f8">' + pydoc.html.heading(
|
head = f'''
|
||||||
'<big><big>%s</big></big>' %
|
<body bgcolor="#f0f0f8">
|
||||||
strong(pydoc.html.escape(str(etype))),
|
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
|
||||||
'#ffffff', '#6622aa', pyver + '<br>' + date) + '''
|
<tr bgcolor="#6622aa">
|
||||||
|
<td valign=bottom> <br>
|
||||||
|
<font color="#ffffff" face="helvetica, arial"> <br>
|
||||||
|
<big><big><strong>{html_escape(str(etype))}</strong></big></big></font></td>
|
||||||
|
<td align=right valign=bottom>
|
||||||
|
<font color="#ffffff" face="helvetica, arial">{pyver}<br>{date}</font></td>
|
||||||
|
</tr></table>
|
||||||
<p>A problem occurred in a Python script. Here is the sequence of
|
<p>A problem occurred in a Python script. Here is the sequence of
|
||||||
function calls leading up to the error, in the order they occurred.</p>'''
|
function calls leading up to the error, in the order they occurred.</p>'''
|
||||||
|
|
||||||
@@ -181,8 +192,8 @@ function calls leading up to the error, in the order they occurred.</p>'''
|
|||||||
|
|
||||||
|
|
||||||
<!-- The above is a description of an error in a Python program, formatted
|
<!-- The above is a description of an error in a Python program, formatted
|
||||||
for a Web browser because the 'cgitb' module was enabled. In case you
|
for a web browser because the 'cgitb' module was enabled. In case you
|
||||||
are not reading this in a Web browser, here is the original traceback:
|
are not reading this in a web browser, here is the original traceback:
|
||||||
|
|
||||||
%s
|
%s
|
||||||
-->
|
-->
|
||||||
|
|||||||
6
Lib/chunk.py
vendored
6
Lib/chunk.py
vendored
@@ -48,6 +48,10 @@ specifies whether or not chunks are aligned on 2-byte boundaries. The
|
|||||||
default is 1, i.e. aligned.
|
default is 1, i.e. aligned.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
warnings._deprecated(__name__, remove=(3, 13))
|
||||||
|
|
||||||
class Chunk:
|
class Chunk:
|
||||||
def __init__(self, file, align=True, bigendian=True, inclheader=False):
|
def __init__(self, file, align=True, bigendian=True, inclheader=False):
|
||||||
import struct
|
import struct
|
||||||
@@ -64,7 +68,7 @@ class Chunk:
|
|||||||
try:
|
try:
|
||||||
self.chunksize = struct.unpack_from(strflag+'L', file.read(4))[0]
|
self.chunksize = struct.unpack_from(strflag+'L', file.read(4))[0]
|
||||||
except struct.error:
|
except struct.error:
|
||||||
raise EOFError
|
raise EOFError from None
|
||||||
if inclheader:
|
if inclheader:
|
||||||
self.chunksize = self.chunksize - 8 # subtract header
|
self.chunksize = self.chunksize - 8 # subtract header
|
||||||
self.size_read = 0
|
self.size_read = 0
|
||||||
|
|||||||
10
Lib/cmd.py
vendored
10
Lib/cmd.py
vendored
@@ -310,10 +310,10 @@ class Cmd:
|
|||||||
names = self.get_names()
|
names = self.get_names()
|
||||||
cmds_doc = []
|
cmds_doc = []
|
||||||
cmds_undoc = []
|
cmds_undoc = []
|
||||||
help = {}
|
topics = set()
|
||||||
for name in names:
|
for name in names:
|
||||||
if name[:5] == 'help_':
|
if name[:5] == 'help_':
|
||||||
help[name[5:]]=1
|
topics.add(name[5:])
|
||||||
names.sort()
|
names.sort()
|
||||||
# There can be duplicates if routines overridden
|
# There can be duplicates if routines overridden
|
||||||
prevname = ''
|
prevname = ''
|
||||||
@@ -323,16 +323,16 @@ class Cmd:
|
|||||||
continue
|
continue
|
||||||
prevname = name
|
prevname = name
|
||||||
cmd=name[3:]
|
cmd=name[3:]
|
||||||
if cmd in help:
|
if cmd in topics:
|
||||||
cmds_doc.append(cmd)
|
cmds_doc.append(cmd)
|
||||||
del help[cmd]
|
topics.remove(cmd)
|
||||||
elif getattr(self, name).__doc__:
|
elif getattr(self, name).__doc__:
|
||||||
cmds_doc.append(cmd)
|
cmds_doc.append(cmd)
|
||||||
else:
|
else:
|
||||||
cmds_undoc.append(cmd)
|
cmds_undoc.append(cmd)
|
||||||
self.stdout.write("%s\n"%str(self.doc_leader))
|
self.stdout.write("%s\n"%str(self.doc_leader))
|
||||||
self.print_topics(self.doc_header, cmds_doc, 15,80)
|
self.print_topics(self.doc_header, cmds_doc, 15,80)
|
||||||
self.print_topics(self.misc_header, list(help.keys()),15,80)
|
self.print_topics(self.misc_header, sorted(topics),15,80)
|
||||||
self.print_topics(self.undoc_header, cmds_undoc, 15,80)
|
self.print_topics(self.undoc_header, cmds_undoc, 15,80)
|
||||||
|
|
||||||
def print_topics(self, header, cmds, cmdlen, maxcol):
|
def print_topics(self, header, cmds, cmdlen, maxcol):
|
||||||
|
|||||||
5
Lib/code.py
vendored
5
Lib/code.py
vendored
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import argparse
|
|
||||||
from codeop import CommandCompiler, compile_command
|
from codeop import CommandCompiler, compile_command
|
||||||
|
|
||||||
__all__ = ["InteractiveInterpreter", "InteractiveConsole", "interact",
|
__all__ = ["InteractiveInterpreter", "InteractiveConsole", "interact",
|
||||||
@@ -41,7 +40,7 @@ class InteractiveInterpreter:
|
|||||||
|
|
||||||
Arguments are as for compile_command().
|
Arguments are as for compile_command().
|
||||||
|
|
||||||
One several things can happen:
|
One of several things can happen:
|
||||||
|
|
||||||
1) The input is incorrect; compile_command() raised an
|
1) The input is incorrect; compile_command() raised an
|
||||||
exception (SyntaxError or OverflowError). A syntax traceback
|
exception (SyntaxError or OverflowError). A syntax traceback
|
||||||
@@ -303,6 +302,8 @@ def interact(banner=None, readfunc=None, local=None, exitmsg=None):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
import argparse
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('-q', action='store_true',
|
parser.add_argument('-q', action='store_true',
|
||||||
help="don't print version and copyright messages")
|
help="don't print version and copyright messages")
|
||||||
|
|||||||
89
Lib/codeop.py
vendored
89
Lib/codeop.py
vendored
@@ -10,30 +10,6 @@ and:
|
|||||||
syntax error (OverflowError and ValueError can be produced by
|
syntax error (OverflowError and ValueError can be produced by
|
||||||
malformed literals).
|
malformed literals).
|
||||||
|
|
||||||
Approach:
|
|
||||||
|
|
||||||
First, check if the source consists entirely of blank lines and
|
|
||||||
comments; if so, replace it with 'pass', because the built-in
|
|
||||||
parser doesn't always do the right thing for these.
|
|
||||||
|
|
||||||
Compile three times: as is, with \n, and with \n\n appended. If it
|
|
||||||
compiles as is, it's complete. If it compiles with one \n appended,
|
|
||||||
we expect more. If it doesn't compile either way, we compare the
|
|
||||||
error we get when compiling with \n or \n\n appended. If the errors
|
|
||||||
are the same, the code is broken. But if the errors are different, we
|
|
||||||
expect more. Not intuitive; not even guaranteed to hold in future
|
|
||||||
releases; but this matches the compiler's behavior from Python 1.4
|
|
||||||
through 2.2, at least.
|
|
||||||
|
|
||||||
Caveat:
|
|
||||||
|
|
||||||
It is possible (but not likely) that the parser stops parsing with a
|
|
||||||
successful outcome before reaching the end of the source; in this
|
|
||||||
case, trailing symbols may be ignored instead of causing an error.
|
|
||||||
For example, a backslash followed by two newlines may be followed by
|
|
||||||
arbitrary garbage. This will be fixed once the API for the parser is
|
|
||||||
better.
|
|
||||||
|
|
||||||
The two interfaces are:
|
The two interfaces are:
|
||||||
|
|
||||||
compile_command(source, filename, symbol):
|
compile_command(source, filename, symbol):
|
||||||
@@ -64,54 +40,50 @@ _features = [getattr(__future__, fname)
|
|||||||
|
|
||||||
__all__ = ["compile_command", "Compile", "CommandCompiler"]
|
__all__ = ["compile_command", "Compile", "CommandCompiler"]
|
||||||
|
|
||||||
PyCF_DONT_IMPLY_DEDENT = 0x200 # Matches pythonrun.h
|
# The following flags match the values from Include/cpython/compile.h
|
||||||
|
# Caveat emptor: These flags are undocumented on purpose and depending
|
||||||
|
# on their effect outside the standard library is **unsupported**.
|
||||||
|
PyCF_DONT_IMPLY_DEDENT = 0x200
|
||||||
|
PyCF_ALLOW_INCOMPLETE_INPUT = 0x4000
|
||||||
|
|
||||||
def _maybe_compile(compiler, source, filename, symbol):
|
def _maybe_compile(compiler, source, filename, symbol):
|
||||||
# Check for source consisting of only blank lines and comments
|
# Check for source consisting of only blank lines and comments.
|
||||||
for line in source.split("\n"):
|
for line in source.split("\n"):
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if line and line[0] != '#':
|
if line and line[0] != '#':
|
||||||
break # Leave it alone
|
break # Leave it alone.
|
||||||
else:
|
else:
|
||||||
if symbol != "eval":
|
if symbol != "eval":
|
||||||
source = "pass" # Replace it with a 'pass' statement
|
source = "pass" # Replace it with a 'pass' statement
|
||||||
|
|
||||||
err = err1 = err2 = None
|
# Disable compiler warnings when checking for incomplete input.
|
||||||
code = code1 = code2 = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
code = compiler(source, filename, symbol)
|
|
||||||
except SyntaxError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Catch syntax warnings after the first compile
|
|
||||||
# to emit warnings (SyntaxWarning, DeprecationWarning) at most once.
|
|
||||||
with warnings.catch_warnings():
|
with warnings.catch_warnings():
|
||||||
warnings.simplefilter("error")
|
warnings.simplefilter("ignore", (SyntaxWarning, DeprecationWarning))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
code1 = compiler(source + "\n", filename, symbol)
|
compiler(source, filename, symbol)
|
||||||
except SyntaxError as e:
|
except SyntaxError: # Let other compile() errors propagate.
|
||||||
err1 = e
|
try:
|
||||||
|
compiler(source + "\n", filename, symbol)
|
||||||
|
return None
|
||||||
|
except SyntaxError as e:
|
||||||
|
if "incomplete input" in str(e):
|
||||||
|
return None
|
||||||
|
# fallthrough
|
||||||
|
|
||||||
try:
|
return compiler(source, filename, symbol)
|
||||||
code2 = compiler(source + "\n\n", filename, symbol)
|
|
||||||
except SyntaxError as e:
|
|
||||||
err2 = e
|
|
||||||
|
|
||||||
try:
|
|
||||||
if code:
|
|
||||||
return code
|
|
||||||
if not code1 and repr(err1) == repr(err2):
|
|
||||||
raise err1
|
|
||||||
finally:
|
|
||||||
err1 = err2 = None
|
|
||||||
|
|
||||||
|
def _is_syntax_error(err1, err2):
|
||||||
|
rep1 = repr(err1)
|
||||||
|
rep2 = repr(err2)
|
||||||
|
if "was never closed" in rep1 and "was never closed" in rep2:
|
||||||
|
return False
|
||||||
|
if rep1 == rep2:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def _compile(source, filename, symbol):
|
def _compile(source, filename, symbol):
|
||||||
return compile(source, filename, symbol, PyCF_DONT_IMPLY_DEDENT)
|
return compile(source, filename, symbol, PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT)
|
||||||
|
|
||||||
|
|
||||||
def compile_command(source, filename="<input>", symbol="single"):
|
def compile_command(source, filename="<input>", symbol="single"):
|
||||||
r"""Compile a command and determine whether it is incomplete.
|
r"""Compile a command and determine whether it is incomplete.
|
||||||
@@ -134,15 +106,13 @@ def compile_command(source, filename="<input>", symbol="single"):
|
|||||||
"""
|
"""
|
||||||
return _maybe_compile(_compile, source, filename, symbol)
|
return _maybe_compile(_compile, source, filename, symbol)
|
||||||
|
|
||||||
|
|
||||||
class Compile:
|
class Compile:
|
||||||
"""Instances of this class behave much like the built-in compile
|
"""Instances of this class behave much like the built-in compile
|
||||||
function, but if one is used to compile text containing a future
|
function, but if one is used to compile text containing a future
|
||||||
statement, it "remembers" and compiles all subsequent program texts
|
statement, it "remembers" and compiles all subsequent program texts
|
||||||
with the statement in force."""
|
with the statement in force."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.flags = PyCF_DONT_IMPLY_DEDENT
|
self.flags = PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT
|
||||||
|
|
||||||
def __call__(self, source, filename, symbol):
|
def __call__(self, source, filename, symbol):
|
||||||
codeob = compile(source, filename, symbol, self.flags, True)
|
codeob = compile(source, filename, symbol, self.flags, True)
|
||||||
@@ -151,7 +121,6 @@ class Compile:
|
|||||||
self.flags |= feature.compiler_flag
|
self.flags |= feature.compiler_flag
|
||||||
return codeob
|
return codeob
|
||||||
|
|
||||||
|
|
||||||
class CommandCompiler:
|
class CommandCompiler:
|
||||||
"""Instances of this class have __call__ methods identical in
|
"""Instances of this class have __call__ methods identical in
|
||||||
signature to compile_command; the difference is that if the
|
signature to compile_command; the difference is that if the
|
||||||
|
|||||||
114
Lib/collections/__init__.py
vendored
114
Lib/collections/__init__.py
vendored
@@ -240,11 +240,19 @@ class OrderedDict(dict):
|
|||||||
is raised.
|
is raised.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
if key in self:
|
marker = self.__marker
|
||||||
result = self[key]
|
result = dict.pop(self, key, marker)
|
||||||
del self[key]
|
if result is not marker:
|
||||||
|
# The same as in __delitem__().
|
||||||
|
link = self.__map.pop(key)
|
||||||
|
link_prev = link.prev
|
||||||
|
link_next = link.next
|
||||||
|
link_prev.next = link_next
|
||||||
|
link_next.prev = link_prev
|
||||||
|
link.prev = None
|
||||||
|
link.next = None
|
||||||
return result
|
return result
|
||||||
if default is self.__marker:
|
if default is marker:
|
||||||
raise KeyError(key)
|
raise KeyError(key)
|
||||||
return default
|
return default
|
||||||
|
|
||||||
@@ -267,10 +275,22 @@ class OrderedDict(dict):
|
|||||||
|
|
||||||
def __reduce__(self):
|
def __reduce__(self):
|
||||||
'Return state information for pickling'
|
'Return state information for pickling'
|
||||||
inst_dict = vars(self).copy()
|
state = self.__getstate__()
|
||||||
for k in vars(OrderedDict()):
|
if state:
|
||||||
inst_dict.pop(k, None)
|
if isinstance(state, tuple):
|
||||||
return self.__class__, (), inst_dict or None, None, iter(self.items())
|
state, slots = state
|
||||||
|
else:
|
||||||
|
slots = {}
|
||||||
|
state = state.copy()
|
||||||
|
slots = slots.copy()
|
||||||
|
for k in vars(OrderedDict()):
|
||||||
|
state.pop(k, None)
|
||||||
|
slots.pop(k, None)
|
||||||
|
if slots:
|
||||||
|
state = state, slots
|
||||||
|
else:
|
||||||
|
state = state or None
|
||||||
|
return self.__class__, (), state, None, iter(self.items())
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
'od.copy() -> a shallow copy of od'
|
'od.copy() -> a shallow copy of od'
|
||||||
@@ -613,11 +633,9 @@ class Counter(dict):
|
|||||||
['A', 'A', 'B', 'B', 'C', 'C']
|
['A', 'A', 'B', 'B', 'C', 'C']
|
||||||
|
|
||||||
# Knuth's example for prime factors of 1836: 2**2 * 3**3 * 17**1
|
# Knuth's example for prime factors of 1836: 2**2 * 3**3 * 17**1
|
||||||
|
>>> import math
|
||||||
>>> prime_factors = Counter({2: 2, 3: 3, 17: 1})
|
>>> prime_factors = Counter({2: 2, 3: 3, 17: 1})
|
||||||
>>> product = 1
|
>>> math.prod(prime_factors.elements())
|
||||||
>>> for factor in prime_factors.elements(): # loop over factors
|
|
||||||
... product *= factor # and multiply them
|
|
||||||
>>> product
|
|
||||||
1836
|
1836
|
||||||
|
|
||||||
Note, if an element's count has been set to zero or is a negative
|
Note, if an element's count has been set to zero or is a negative
|
||||||
@@ -714,42 +732,6 @@ class Counter(dict):
|
|||||||
if elem in self:
|
if elem in self:
|
||||||
super().__delitem__(elem)
|
super().__delitem__(elem)
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
'True if all counts agree. Missing counts are treated as zero.'
|
|
||||||
if not isinstance(other, Counter):
|
|
||||||
return NotImplemented
|
|
||||||
return all(self[e] == other[e] for c in (self, other) for e in c)
|
|
||||||
|
|
||||||
def __ne__(self, other):
|
|
||||||
'True if any counts disagree. Missing counts are treated as zero.'
|
|
||||||
if not isinstance(other, Counter):
|
|
||||||
return NotImplemented
|
|
||||||
return not self == other
|
|
||||||
|
|
||||||
def __le__(self, other):
|
|
||||||
'True if all counts in self are a subset of those in other.'
|
|
||||||
if not isinstance(other, Counter):
|
|
||||||
return NotImplemented
|
|
||||||
return all(self[e] <= other[e] for c in (self, other) for e in c)
|
|
||||||
|
|
||||||
def __lt__(self, other):
|
|
||||||
'True if all counts in self are a proper subset of those in other.'
|
|
||||||
if not isinstance(other, Counter):
|
|
||||||
return NotImplemented
|
|
||||||
return self <= other and self != other
|
|
||||||
|
|
||||||
def __ge__(self, other):
|
|
||||||
'True if all counts in self are a superset of those in other.'
|
|
||||||
if not isinstance(other, Counter):
|
|
||||||
return NotImplemented
|
|
||||||
return all(self[e] >= other[e] for c in (self, other) for e in c)
|
|
||||||
|
|
||||||
def __gt__(self, other):
|
|
||||||
'True if all counts in self are a proper superset of those in other.'
|
|
||||||
if not isinstance(other, Counter):
|
|
||||||
return NotImplemented
|
|
||||||
return self >= other and self != other
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
if not self:
|
if not self:
|
||||||
return f'{self.__class__.__name__}()'
|
return f'{self.__class__.__name__}()'
|
||||||
@@ -795,6 +777,42 @@ class Counter(dict):
|
|||||||
# (cp >= cq) == (sp >= sq)
|
# (cp >= cq) == (sp >= sq)
|
||||||
# (cp > cq) == (sp > sq)
|
# (cp > cq) == (sp > sq)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
'True if all counts agree. Missing counts are treated as zero.'
|
||||||
|
if not isinstance(other, Counter):
|
||||||
|
return NotImplemented
|
||||||
|
return all(self[e] == other[e] for c in (self, other) for e in c)
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
'True if any counts disagree. Missing counts are treated as zero.'
|
||||||
|
if not isinstance(other, Counter):
|
||||||
|
return NotImplemented
|
||||||
|
return not self == other
|
||||||
|
|
||||||
|
def __le__(self, other):
|
||||||
|
'True if all counts in self are a subset of those in other.'
|
||||||
|
if not isinstance(other, Counter):
|
||||||
|
return NotImplemented
|
||||||
|
return all(self[e] <= other[e] for c in (self, other) for e in c)
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
'True if all counts in self are a proper subset of those in other.'
|
||||||
|
if not isinstance(other, Counter):
|
||||||
|
return NotImplemented
|
||||||
|
return self <= other and self != other
|
||||||
|
|
||||||
|
def __ge__(self, other):
|
||||||
|
'True if all counts in self are a superset of those in other.'
|
||||||
|
if not isinstance(other, Counter):
|
||||||
|
return NotImplemented
|
||||||
|
return all(self[e] >= other[e] for c in (self, other) for e in c)
|
||||||
|
|
||||||
|
def __gt__(self, other):
|
||||||
|
'True if all counts in self are a proper superset of those in other.'
|
||||||
|
if not isinstance(other, Counter):
|
||||||
|
return NotImplemented
|
||||||
|
return self >= other and self != other
|
||||||
|
|
||||||
def __add__(self, other):
|
def __add__(self, other):
|
||||||
'''Add counts from two counters.
|
'''Add counts from two counters.
|
||||||
|
|
||||||
|
|||||||
28
Lib/colorsys.py
vendored
28
Lib/colorsys.py
vendored
@@ -1,10 +1,14 @@
|
|||||||
"""Conversion functions between RGB and other color systems.
|
"""Conversion functions between RGB and other color systems.
|
||||||
|
|
||||||
This modules provides two functions for each color system ABC:
|
This modules provides two functions for each color system ABC:
|
||||||
|
|
||||||
rgb_to_abc(r, g, b) --> a, b, c
|
rgb_to_abc(r, g, b) --> a, b, c
|
||||||
abc_to_rgb(a, b, c) --> r, g, b
|
abc_to_rgb(a, b, c) --> r, g, b
|
||||||
|
|
||||||
All inputs and outputs are triples of floats in the range [0.0...1.0]
|
All inputs and outputs are triples of floats in the range [0.0...1.0]
|
||||||
(with the exception of I and Q, which covers a slightly larger range).
|
(with the exception of I and Q, which covers a slightly larger range).
|
||||||
Inputs outside the valid range may cause exceptions or invalid outputs.
|
Inputs outside the valid range may cause exceptions or invalid outputs.
|
||||||
|
|
||||||
Supported color systems:
|
Supported color systems:
|
||||||
RGB: Red, Green, Blue components
|
RGB: Red, Green, Blue components
|
||||||
YIQ: Luminance, Chrominance (used by composite video signals)
|
YIQ: Luminance, Chrominance (used by composite video signals)
|
||||||
@@ -71,17 +75,18 @@ def yiq_to_rgb(y, i, q):
|
|||||||
def rgb_to_hls(r, g, b):
|
def rgb_to_hls(r, g, b):
|
||||||
maxc = max(r, g, b)
|
maxc = max(r, g, b)
|
||||||
minc = min(r, g, b)
|
minc = min(r, g, b)
|
||||||
# XXX Can optimize (maxc+minc) and (maxc-minc)
|
sumc = (maxc+minc)
|
||||||
l = (minc+maxc)/2.0
|
rangec = (maxc-minc)
|
||||||
|
l = sumc/2.0
|
||||||
if minc == maxc:
|
if minc == maxc:
|
||||||
return 0.0, l, 0.0
|
return 0.0, l, 0.0
|
||||||
if l <= 0.5:
|
if l <= 0.5:
|
||||||
s = (maxc-minc) / (maxc+minc)
|
s = rangec / sumc
|
||||||
else:
|
else:
|
||||||
s = (maxc-minc) / (2.0-maxc-minc)
|
s = rangec / (2.0-sumc)
|
||||||
rc = (maxc-r) / (maxc-minc)
|
rc = (maxc-r) / rangec
|
||||||
gc = (maxc-g) / (maxc-minc)
|
gc = (maxc-g) / rangec
|
||||||
bc = (maxc-b) / (maxc-minc)
|
bc = (maxc-b) / rangec
|
||||||
if r == maxc:
|
if r == maxc:
|
||||||
h = bc-gc
|
h = bc-gc
|
||||||
elif g == maxc:
|
elif g == maxc:
|
||||||
@@ -120,13 +125,14 @@ def _v(m1, m2, hue):
|
|||||||
def rgb_to_hsv(r, g, b):
|
def rgb_to_hsv(r, g, b):
|
||||||
maxc = max(r, g, b)
|
maxc = max(r, g, b)
|
||||||
minc = min(r, g, b)
|
minc = min(r, g, b)
|
||||||
|
rangec = (maxc-minc)
|
||||||
v = maxc
|
v = maxc
|
||||||
if minc == maxc:
|
if minc == maxc:
|
||||||
return 0.0, 0.0, v
|
return 0.0, 0.0, v
|
||||||
s = (maxc-minc) / maxc
|
s = rangec / maxc
|
||||||
rc = (maxc-r) / (maxc-minc)
|
rc = (maxc-r) / rangec
|
||||||
gc = (maxc-g) / (maxc-minc)
|
gc = (maxc-g) / rangec
|
||||||
bc = (maxc-b) / (maxc-minc)
|
bc = (maxc-b) / rangec
|
||||||
if r == maxc:
|
if r == maxc:
|
||||||
h = bc-gc
|
h = bc-gc
|
||||||
elif g == maxc:
|
elif g == maxc:
|
||||||
|
|||||||
3
Lib/concurrent/futures/thread.py
vendored
3
Lib/concurrent/futures/thread.py
vendored
@@ -37,7 +37,8 @@ def _python_exit():
|
|||||||
threading._register_atexit(_python_exit)
|
threading._register_atexit(_python_exit)
|
||||||
|
|
||||||
# At fork, reinitialize the `_global_shutdown_lock` lock in the child process
|
# At fork, reinitialize the `_global_shutdown_lock` lock in the child process
|
||||||
if hasattr(os, 'register_at_fork'):
|
# TODO RUSTPYTHON - _at_fork_reinit is not implemented yet
|
||||||
|
if hasattr(os, 'register_at_fork') and hasattr(_global_shutdown_lock, '_at_fork_reinit'):
|
||||||
os.register_at_fork(before=_global_shutdown_lock.acquire,
|
os.register_at_fork(before=_global_shutdown_lock.acquire,
|
||||||
after_in_child=_global_shutdown_lock._at_fork_reinit,
|
after_in_child=_global_shutdown_lock._at_fork_reinit,
|
||||||
after_in_parent=_global_shutdown_lock.release)
|
after_in_parent=_global_shutdown_lock.release)
|
||||||
|
|||||||
153
Lib/configparser.py
vendored
153
Lib/configparser.py
vendored
@@ -19,36 +19,37 @@ ConfigParser -- responsible for parsing a list of
|
|||||||
inline_comment_prefixes=None, strict=True,
|
inline_comment_prefixes=None, strict=True,
|
||||||
empty_lines_in_values=True, default_section='DEFAULT',
|
empty_lines_in_values=True, default_section='DEFAULT',
|
||||||
interpolation=<unset>, converters=<unset>):
|
interpolation=<unset>, converters=<unset>):
|
||||||
Create the parser. When `defaults' is given, it is initialized into the
|
|
||||||
|
Create the parser. When `defaults` is given, it is initialized into the
|
||||||
dictionary or intrinsic defaults. The keys must be strings, the values
|
dictionary or intrinsic defaults. The keys must be strings, the values
|
||||||
must be appropriate for %()s string interpolation.
|
must be appropriate for %()s string interpolation.
|
||||||
|
|
||||||
When `dict_type' is given, it will be used to create the dictionary
|
When `dict_type` is given, it will be used to create the dictionary
|
||||||
objects for the list of sections, for the options within a section, and
|
objects for the list of sections, for the options within a section, and
|
||||||
for the default values.
|
for the default values.
|
||||||
|
|
||||||
When `delimiters' is given, it will be used as the set of substrings
|
When `delimiters` is given, it will be used as the set of substrings
|
||||||
that divide keys from values.
|
that divide keys from values.
|
||||||
|
|
||||||
When `comment_prefixes' is given, it will be used as the set of
|
When `comment_prefixes` is given, it will be used as the set of
|
||||||
substrings that prefix comments in empty lines. Comments can be
|
substrings that prefix comments in empty lines. Comments can be
|
||||||
indented.
|
indented.
|
||||||
|
|
||||||
When `inline_comment_prefixes' is given, it will be used as the set of
|
When `inline_comment_prefixes` is given, it will be used as the set of
|
||||||
substrings that prefix comments in non-empty lines.
|
substrings that prefix comments in non-empty lines.
|
||||||
|
|
||||||
When `strict` is True, the parser won't allow for any section or option
|
When `strict` is True, the parser won't allow for any section or option
|
||||||
duplicates while reading from a single source (file, string or
|
duplicates while reading from a single source (file, string or
|
||||||
dictionary). Default is True.
|
dictionary). Default is True.
|
||||||
|
|
||||||
When `empty_lines_in_values' is False (default: True), each empty line
|
When `empty_lines_in_values` is False (default: True), each empty line
|
||||||
marks the end of an option. Otherwise, internal empty lines of
|
marks the end of an option. Otherwise, internal empty lines of
|
||||||
a multiline option are kept as part of the value.
|
a multiline option are kept as part of the value.
|
||||||
|
|
||||||
When `allow_no_value' is True (default: False), options without
|
When `allow_no_value` is True (default: False), options without
|
||||||
values are accepted; the value presented for these is None.
|
values are accepted; the value presented for these is None.
|
||||||
|
|
||||||
When `default_section' is given, the name of the special section is
|
When `default_section` is given, the name of the special section is
|
||||||
named accordingly. By default it is called ``"DEFAULT"`` but this can
|
named accordingly. By default it is called ``"DEFAULT"`` but this can
|
||||||
be customized to point to any other valid section name. Its current
|
be customized to point to any other valid section name. Its current
|
||||||
value can be retrieved using the ``parser_instance.default_section``
|
value can be retrieved using the ``parser_instance.default_section``
|
||||||
@@ -56,7 +57,7 @@ ConfigParser -- responsible for parsing a list of
|
|||||||
|
|
||||||
When `interpolation` is given, it should be an Interpolation subclass
|
When `interpolation` is given, it should be an Interpolation subclass
|
||||||
instance. It will be used as the handler for option value
|
instance. It will be used as the handler for option value
|
||||||
pre-processing when using getters. RawConfigParser object s don't do
|
pre-processing when using getters. RawConfigParser objects don't do
|
||||||
any sort of interpolation, whereas ConfigParser uses an instance of
|
any sort of interpolation, whereas ConfigParser uses an instance of
|
||||||
BasicInterpolation. The library also provides a ``zc.buildbot``
|
BasicInterpolation. The library also provides a ``zc.buildbot``
|
||||||
inspired ExtendedInterpolation implementation.
|
inspired ExtendedInterpolation implementation.
|
||||||
@@ -80,14 +81,14 @@ ConfigParser -- responsible for parsing a list of
|
|||||||
Return list of configuration options for the named section.
|
Return list of configuration options for the named section.
|
||||||
|
|
||||||
read(filenames, encoding=None)
|
read(filenames, encoding=None)
|
||||||
Read and parse the list of named configuration files, given by
|
Read and parse the iterable of named configuration files, given by
|
||||||
name. A single filename is also allowed. Non-existing files
|
name. A single filename is also allowed. Non-existing files
|
||||||
are ignored. Return list of successfully read files.
|
are ignored. Return list of successfully read files.
|
||||||
|
|
||||||
read_file(f, filename=None)
|
read_file(f, filename=None)
|
||||||
Read and parse one configuration file, given as a file object.
|
Read and parse one configuration file, given as a file object.
|
||||||
The filename defaults to f.name; it is only used in error
|
The filename defaults to f.name; it is only used in error
|
||||||
messages (if f has no `name' attribute, the string `<???>' is used).
|
messages (if f has no `name` attribute, the string `<???>` is used).
|
||||||
|
|
||||||
read_string(string)
|
read_string(string)
|
||||||
Read configuration from a given string.
|
Read configuration from a given string.
|
||||||
@@ -103,9 +104,9 @@ ConfigParser -- responsible for parsing a list of
|
|||||||
Return a string value for the named option. All % interpolations are
|
Return a string value for the named option. All % interpolations are
|
||||||
expanded in the return values, based on the defaults passed into the
|
expanded in the return values, based on the defaults passed into the
|
||||||
constructor and the DEFAULT section. Additional substitutions may be
|
constructor and the DEFAULT section. Additional substitutions may be
|
||||||
provided using the `vars' argument, which must be a dictionary whose
|
provided using the `vars` argument, which must be a dictionary whose
|
||||||
contents override any pre-existing defaults. If `option' is a key in
|
contents override any pre-existing defaults. If `option` is a key in
|
||||||
`vars', the value from `vars' is used.
|
`vars`, the value from `vars` is used.
|
||||||
|
|
||||||
getint(section, options, raw=False, vars=None, fallback=_UNSET)
|
getint(section, options, raw=False, vars=None, fallback=_UNSET)
|
||||||
Like get(), but convert value to an integer.
|
Like get(), but convert value to an integer.
|
||||||
@@ -134,15 +135,16 @@ ConfigParser -- responsible for parsing a list of
|
|||||||
|
|
||||||
write(fp, space_around_delimiters=True)
|
write(fp, space_around_delimiters=True)
|
||||||
Write the configuration state in .ini format. If
|
Write the configuration state in .ini format. If
|
||||||
`space_around_delimiters' is True (the default), delimiters
|
`space_around_delimiters` is True (the default), delimiters
|
||||||
between keys and values are surrounded by spaces.
|
between keys and values are surrounded by spaces.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from collections.abc import MutableMapping
|
from collections.abc import MutableMapping
|
||||||
from collections import OrderedDict as _default_dict, ChainMap as _ChainMap
|
from collections import ChainMap as _ChainMap
|
||||||
import functools
|
import functools
|
||||||
import io
|
import io
|
||||||
import itertools
|
import itertools
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
@@ -156,6 +158,7 @@ __all__ = ["NoSectionError", "DuplicateOptionError", "DuplicateSectionError",
|
|||||||
"LegacyInterpolation", "SectionProxy", "ConverterMapping",
|
"LegacyInterpolation", "SectionProxy", "ConverterMapping",
|
||||||
"DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"]
|
"DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"]
|
||||||
|
|
||||||
|
_default_dict = dict
|
||||||
DEFAULTSECT = "DEFAULT"
|
DEFAULTSECT = "DEFAULT"
|
||||||
|
|
||||||
MAX_INTERPOLATION_DEPTH = 10
|
MAX_INTERPOLATION_DEPTH = 10
|
||||||
@@ -314,7 +317,7 @@ class ParsingError(Error):
|
|||||||
def filename(self):
|
def filename(self):
|
||||||
"""Deprecated, use `source'."""
|
"""Deprecated, use `source'."""
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"The 'filename' attribute will be removed in future versions. "
|
"The 'filename' attribute will be removed in Python 3.12. "
|
||||||
"Use 'source' instead.",
|
"Use 'source' instead.",
|
||||||
DeprecationWarning, stacklevel=2
|
DeprecationWarning, stacklevel=2
|
||||||
)
|
)
|
||||||
@@ -324,7 +327,7 @@ class ParsingError(Error):
|
|||||||
def filename(self, value):
|
def filename(self, value):
|
||||||
"""Deprecated, user `source'."""
|
"""Deprecated, user `source'."""
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"The 'filename' attribute will be removed in future versions. "
|
"The 'filename' attribute will be removed in Python 3.12. "
|
||||||
"Use 'source' instead.",
|
"Use 'source' instead.",
|
||||||
DeprecationWarning, stacklevel=2
|
DeprecationWarning, stacklevel=2
|
||||||
)
|
)
|
||||||
@@ -350,7 +353,7 @@ class MissingSectionHeaderError(ParsingError):
|
|||||||
|
|
||||||
|
|
||||||
# Used in parser getters to indicate the default behaviour when a specific
|
# Used in parser getters to indicate the default behaviour when a specific
|
||||||
# option is not found it to raise an exception. Created to enable `None' as
|
# option is not found it to raise an exception. Created to enable `None` as
|
||||||
# a valid fallback value.
|
# a valid fallback value.
|
||||||
_UNSET = object()
|
_UNSET = object()
|
||||||
|
|
||||||
@@ -384,7 +387,7 @@ class BasicInterpolation(Interpolation):
|
|||||||
would resolve the "%(dir)s" to the value of dir. All reference
|
would resolve the "%(dir)s" to the value of dir. All reference
|
||||||
expansions are done late, on demand. If a user needs to use a bare % in
|
expansions are done late, on demand. If a user needs to use a bare % in
|
||||||
a configuration file, she can escape it by writing %%. Other % usage
|
a configuration file, she can escape it by writing %%. Other % usage
|
||||||
is considered a user error and raises `InterpolationSyntaxError'."""
|
is considered a user error and raises `InterpolationSyntaxError`."""
|
||||||
|
|
||||||
_KEYCRE = re.compile(r"%\(([^)]+)\)s")
|
_KEYCRE = re.compile(r"%\(([^)]+)\)s")
|
||||||
|
|
||||||
@@ -445,7 +448,7 @@ class BasicInterpolation(Interpolation):
|
|||||||
|
|
||||||
class ExtendedInterpolation(Interpolation):
|
class ExtendedInterpolation(Interpolation):
|
||||||
"""Advanced variant of interpolation, supports the syntax used by
|
"""Advanced variant of interpolation, supports the syntax used by
|
||||||
`zc.buildout'. Enables interpolation between sections."""
|
`zc.buildout`. Enables interpolation between sections."""
|
||||||
|
|
||||||
_KEYCRE = re.compile(r"\$\{([^}]+)\}")
|
_KEYCRE = re.compile(r"\$\{([^}]+)\}")
|
||||||
|
|
||||||
@@ -523,6 +526,15 @@ class LegacyInterpolation(Interpolation):
|
|||||||
|
|
||||||
_KEYCRE = re.compile(r"%\(([^)]*)\)s|.")
|
_KEYCRE = re.compile(r"%\(([^)]*)\)s|.")
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
warnings.warn(
|
||||||
|
"LegacyInterpolation has been deprecated since Python 3.2 "
|
||||||
|
"and will be removed from the configparser module in Python 3.13. "
|
||||||
|
"Use BasicInterpolation or ExtendedInterpolation instead.",
|
||||||
|
DeprecationWarning, stacklevel=2
|
||||||
|
)
|
||||||
|
|
||||||
def before_get(self, parser, section, option, value, vars):
|
def before_get(self, parser, section, option, value, vars):
|
||||||
rawval = value
|
rawval = value
|
||||||
depth = MAX_INTERPOLATION_DEPTH
|
depth = MAX_INTERPOLATION_DEPTH
|
||||||
@@ -561,7 +573,7 @@ class RawConfigParser(MutableMapping):
|
|||||||
# Regular expressions for parsing section headers and options
|
# Regular expressions for parsing section headers and options
|
||||||
_SECT_TMPL = r"""
|
_SECT_TMPL = r"""
|
||||||
\[ # [
|
\[ # [
|
||||||
(?P<header>[^]]+) # very permissive!
|
(?P<header>.+) # very permissive!
|
||||||
\] # ]
|
\] # ]
|
||||||
"""
|
"""
|
||||||
_OPT_TMPL = r"""
|
_OPT_TMPL = r"""
|
||||||
@@ -609,9 +621,6 @@ class RawConfigParser(MutableMapping):
|
|||||||
self._converters = ConverterMapping(self)
|
self._converters = ConverterMapping(self)
|
||||||
self._proxies = self._dict()
|
self._proxies = self._dict()
|
||||||
self._proxies[default_section] = SectionProxy(self, default_section)
|
self._proxies[default_section] = SectionProxy(self, default_section)
|
||||||
if defaults:
|
|
||||||
for key, value in defaults.items():
|
|
||||||
self._defaults[self.optionxform(key)] = value
|
|
||||||
self._delimiters = tuple(delimiters)
|
self._delimiters = tuple(delimiters)
|
||||||
if delimiters == ('=', ':'):
|
if delimiters == ('=', ':'):
|
||||||
self._optcre = self.OPTCRE_NV if allow_no_value else self.OPTCRE
|
self._optcre = self.OPTCRE_NV if allow_no_value else self.OPTCRE
|
||||||
@@ -634,8 +643,15 @@ class RawConfigParser(MutableMapping):
|
|||||||
self._interpolation = self._DEFAULT_INTERPOLATION
|
self._interpolation = self._DEFAULT_INTERPOLATION
|
||||||
if self._interpolation is None:
|
if self._interpolation is None:
|
||||||
self._interpolation = Interpolation()
|
self._interpolation = Interpolation()
|
||||||
|
if not isinstance(self._interpolation, Interpolation):
|
||||||
|
raise TypeError(
|
||||||
|
f"interpolation= must be None or an instance of Interpolation;"
|
||||||
|
f" got an object of type {type(self._interpolation)}"
|
||||||
|
)
|
||||||
if converters is not _UNSET:
|
if converters is not _UNSET:
|
||||||
self._converters.update(converters)
|
self._converters.update(converters)
|
||||||
|
if defaults:
|
||||||
|
self._read_defaults(defaults)
|
||||||
|
|
||||||
def defaults(self):
|
def defaults(self):
|
||||||
return self._defaults
|
return self._defaults
|
||||||
@@ -676,19 +692,20 @@ class RawConfigParser(MutableMapping):
|
|||||||
return list(opts.keys())
|
return list(opts.keys())
|
||||||
|
|
||||||
def read(self, filenames, encoding=None):
|
def read(self, filenames, encoding=None):
|
||||||
"""Read and parse a filename or a list of filenames.
|
"""Read and parse a filename or an iterable of filenames.
|
||||||
|
|
||||||
Files that cannot be opened are silently ignored; this is
|
Files that cannot be opened are silently ignored; this is
|
||||||
designed so that you can specify a list of potential
|
designed so that you can specify an iterable of potential
|
||||||
configuration file locations (e.g. current directory, user's
|
configuration file locations (e.g. current directory, user's
|
||||||
home directory, systemwide directory), and all existing
|
home directory, systemwide directory), and all existing
|
||||||
configuration files in the list will be read. A single
|
configuration files in the iterable will be read. A single
|
||||||
filename may also be given.
|
filename may also be given.
|
||||||
|
|
||||||
Return list of successfully read files.
|
Return list of successfully read files.
|
||||||
"""
|
"""
|
||||||
if isinstance(filenames, str):
|
if isinstance(filenames, (str, bytes, os.PathLike)):
|
||||||
filenames = [filenames]
|
filenames = [filenames]
|
||||||
|
encoding = io.text_encoding(encoding)
|
||||||
read_ok = []
|
read_ok = []
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
try:
|
try:
|
||||||
@@ -696,16 +713,18 @@ class RawConfigParser(MutableMapping):
|
|||||||
self._read(fp, filename)
|
self._read(fp, filename)
|
||||||
except OSError:
|
except OSError:
|
||||||
continue
|
continue
|
||||||
|
if isinstance(filename, os.PathLike):
|
||||||
|
filename = os.fspath(filename)
|
||||||
read_ok.append(filename)
|
read_ok.append(filename)
|
||||||
return read_ok
|
return read_ok
|
||||||
|
|
||||||
def read_file(self, f, source=None):
|
def read_file(self, f, source=None):
|
||||||
"""Like read() but the argument must be a file-like object.
|
"""Like read() but the argument must be a file-like object.
|
||||||
|
|
||||||
The `f' argument must be iterable, returning one line at a time.
|
The `f` argument must be iterable, returning one line at a time.
|
||||||
Optional second argument is the `source' specifying the name of the
|
Optional second argument is the `source` specifying the name of the
|
||||||
file being read. If not given, it is taken from f.name. If `f' has no
|
file being read. If not given, it is taken from f.name. If `f` has no
|
||||||
`name' attribute, `<???>' is used.
|
`name` attribute, `<???>` is used.
|
||||||
"""
|
"""
|
||||||
if source is None:
|
if source is None:
|
||||||
try:
|
try:
|
||||||
@@ -729,7 +748,7 @@ class RawConfigParser(MutableMapping):
|
|||||||
All types held in the dictionary are converted to strings during
|
All types held in the dictionary are converted to strings during
|
||||||
reading, including section names, option names and keys.
|
reading, including section names, option names and keys.
|
||||||
|
|
||||||
Optional second argument is the `source' specifying the name of the
|
Optional second argument is the `source` specifying the name of the
|
||||||
dictionary being read.
|
dictionary being read.
|
||||||
"""
|
"""
|
||||||
elements_added = set()
|
elements_added = set()
|
||||||
@@ -753,7 +772,7 @@ class RawConfigParser(MutableMapping):
|
|||||||
def readfp(self, fp, filename=None):
|
def readfp(self, fp, filename=None):
|
||||||
"""Deprecated, use read_file instead."""
|
"""Deprecated, use read_file instead."""
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"This method will be removed in future versions. "
|
"This method will be removed in Python 3.12. "
|
||||||
"Use 'parser.read_file()' instead.",
|
"Use 'parser.read_file()' instead.",
|
||||||
DeprecationWarning, stacklevel=2
|
DeprecationWarning, stacklevel=2
|
||||||
)
|
)
|
||||||
@@ -762,15 +781,15 @@ class RawConfigParser(MutableMapping):
|
|||||||
def get(self, section, option, *, raw=False, vars=None, fallback=_UNSET):
|
def get(self, section, option, *, raw=False, vars=None, fallback=_UNSET):
|
||||||
"""Get an option value for a given section.
|
"""Get an option value for a given section.
|
||||||
|
|
||||||
If `vars' is provided, it must be a dictionary. The option is looked up
|
If `vars` is provided, it must be a dictionary. The option is looked up
|
||||||
in `vars' (if provided), `section', and in `DEFAULTSECT' in that order.
|
in `vars` (if provided), `section`, and in `DEFAULTSECT` in that order.
|
||||||
If the key is not found and `fallback' is provided, it is used as
|
If the key is not found and `fallback` is provided, it is used as
|
||||||
a fallback value. `None' can be provided as a `fallback' value.
|
a fallback value. `None` can be provided as a `fallback` value.
|
||||||
|
|
||||||
If interpolation is enabled and the optional argument `raw' is False,
|
If interpolation is enabled and the optional argument `raw` is False,
|
||||||
all interpolations are expanded in the return values.
|
all interpolations are expanded in the return values.
|
||||||
|
|
||||||
Arguments `raw', `vars', and `fallback' are keyword only.
|
Arguments `raw`, `vars`, and `fallback` are keyword only.
|
||||||
|
|
||||||
The section DEFAULT is special.
|
The section DEFAULT is special.
|
||||||
"""
|
"""
|
||||||
@@ -830,8 +849,8 @@ class RawConfigParser(MutableMapping):
|
|||||||
|
|
||||||
All % interpolations are expanded in the return values, based on the
|
All % interpolations are expanded in the return values, based on the
|
||||||
defaults passed into the constructor, unless the optional argument
|
defaults passed into the constructor, unless the optional argument
|
||||||
`raw' is true. Additional substitutions may be provided using the
|
`raw` is true. Additional substitutions may be provided using the
|
||||||
`vars' argument, which must be a dictionary whose contents overrides
|
`vars` argument, which must be a dictionary whose contents overrides
|
||||||
any pre-existing defaults.
|
any pre-existing defaults.
|
||||||
|
|
||||||
The section DEFAULT is special.
|
The section DEFAULT is special.
|
||||||
@@ -844,6 +863,7 @@ class RawConfigParser(MutableMapping):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
if section != self.default_section:
|
if section != self.default_section:
|
||||||
raise NoSectionError(section)
|
raise NoSectionError(section)
|
||||||
|
orig_keys = list(d.keys())
|
||||||
# Update with the entry specific variables
|
# Update with the entry specific variables
|
||||||
if vars:
|
if vars:
|
||||||
for key, value in vars.items():
|
for key, value in vars.items():
|
||||||
@@ -852,7 +872,7 @@ class RawConfigParser(MutableMapping):
|
|||||||
section, option, d[option], d)
|
section, option, d[option], d)
|
||||||
if raw:
|
if raw:
|
||||||
value_getter = lambda option: d[option]
|
value_getter = lambda option: d[option]
|
||||||
return [(option, value_getter(option)) for option in d.keys()]
|
return [(option, value_getter(option)) for option in orig_keys]
|
||||||
|
|
||||||
def popitem(self):
|
def popitem(self):
|
||||||
"""Remove a section from the parser and return it as
|
"""Remove a section from the parser and return it as
|
||||||
@@ -872,8 +892,8 @@ class RawConfigParser(MutableMapping):
|
|||||||
|
|
||||||
def has_option(self, section, option):
|
def has_option(self, section, option):
|
||||||
"""Check for the existence of a given option in a given section.
|
"""Check for the existence of a given option in a given section.
|
||||||
If the specified `section' is None or an empty string, DEFAULT is
|
If the specified `section` is None or an empty string, DEFAULT is
|
||||||
assumed. If the specified `section' does not exist, returns False."""
|
assumed. If the specified `section` does not exist, returns False."""
|
||||||
if not section or section == self.default_section:
|
if not section or section == self.default_section:
|
||||||
option = self.optionxform(option)
|
option = self.optionxform(option)
|
||||||
return option in self._defaults
|
return option in self._defaults
|
||||||
@@ -901,8 +921,11 @@ class RawConfigParser(MutableMapping):
|
|||||||
def write(self, fp, space_around_delimiters=True):
|
def write(self, fp, space_around_delimiters=True):
|
||||||
"""Write an .ini-format representation of the configuration state.
|
"""Write an .ini-format representation of the configuration state.
|
||||||
|
|
||||||
If `space_around_delimiters' is True (the default), delimiters
|
If `space_around_delimiters` is True (the default), delimiters
|
||||||
between keys and values are surrounded by spaces.
|
between keys and values are surrounded by spaces.
|
||||||
|
|
||||||
|
Please note that comments in the original configuration file are not
|
||||||
|
preserved when writing the configuration back.
|
||||||
"""
|
"""
|
||||||
if space_around_delimiters:
|
if space_around_delimiters:
|
||||||
d = " {} ".format(self._delimiters[0])
|
d = " {} ".format(self._delimiters[0])
|
||||||
@@ -916,7 +939,7 @@ class RawConfigParser(MutableMapping):
|
|||||||
self._sections[section].items(), d)
|
self._sections[section].items(), d)
|
||||||
|
|
||||||
def _write_section(self, fp, section_name, section_items, delimiter):
|
def _write_section(self, fp, section_name, section_items, delimiter):
|
||||||
"""Write a single section to the specified `fp'."""
|
"""Write a single section to the specified `fp`."""
|
||||||
fp.write("[{}]\n".format(section_name))
|
fp.write("[{}]\n".format(section_name))
|
||||||
for key, value in section_items:
|
for key, value in section_items:
|
||||||
value = self._interpolation.before_write(self, section_name, key,
|
value = self._interpolation.before_write(self, section_name, key,
|
||||||
@@ -959,7 +982,8 @@ class RawConfigParser(MutableMapping):
|
|||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
# To conform with the mapping protocol, overwrites existing values in
|
# To conform with the mapping protocol, overwrites existing values in
|
||||||
# the section.
|
# the section.
|
||||||
|
if key in self and self[key] is value:
|
||||||
|
return
|
||||||
# XXX this is not atomic if read_dict fails at any point. Then again,
|
# XXX this is not atomic if read_dict fails at any point. Then again,
|
||||||
# no update method in configparser is atomic in this implementation.
|
# no update method in configparser is atomic in this implementation.
|
||||||
if key == self.default_section:
|
if key == self.default_section:
|
||||||
@@ -989,8 +1013,8 @@ class RawConfigParser(MutableMapping):
|
|||||||
"""Parse a sectioned configuration file.
|
"""Parse a sectioned configuration file.
|
||||||
|
|
||||||
Each section in a configuration file contains a header, indicated by
|
Each section in a configuration file contains a header, indicated by
|
||||||
a name in square brackets (`[]'), plus key/value options, indicated by
|
a name in square brackets (`[]`), plus key/value options, indicated by
|
||||||
`name' and `value' delimited with a specific substring (`=' or `:' by
|
`name` and `value` delimited with a specific substring (`=` or `:` by
|
||||||
default).
|
default).
|
||||||
|
|
||||||
Values can span multiple lines, as long as they are indented deeper
|
Values can span multiple lines, as long as they are indented deeper
|
||||||
@@ -998,9 +1022,9 @@ class RawConfigParser(MutableMapping):
|
|||||||
lines may be treated as parts of multiline values or ignored.
|
lines may be treated as parts of multiline values or ignored.
|
||||||
|
|
||||||
Configuration files may include comments, prefixed by specific
|
Configuration files may include comments, prefixed by specific
|
||||||
characters (`#' and `;' by default). Comments may appear on their own
|
characters (`#` and `;` by default). Comments may appear on their own
|
||||||
in an otherwise empty line or may be entered in lines holding values or
|
in an otherwise empty line or may be entered in lines holding values or
|
||||||
section names.
|
section names. Please note that comments get stripped off when reading configuration files.
|
||||||
"""
|
"""
|
||||||
elements_added = set()
|
elements_added = set()
|
||||||
cursect = None # None, or a dictionary
|
cursect = None # None, or a dictionary
|
||||||
@@ -1119,6 +1143,12 @@ class RawConfigParser(MutableMapping):
|
|||||||
section,
|
section,
|
||||||
name, val)
|
name, val)
|
||||||
|
|
||||||
|
def _read_defaults(self, defaults):
|
||||||
|
"""Read the defaults passed in the initializer.
|
||||||
|
Note: values can be non-string."""
|
||||||
|
for key, value in defaults.items():
|
||||||
|
self._defaults[self.optionxform(key)] = value
|
||||||
|
|
||||||
def _handle_error(self, exc, fpname, lineno, line):
|
def _handle_error(self, exc, fpname, lineno, line):
|
||||||
if not exc:
|
if not exc:
|
||||||
exc = ParsingError(fpname)
|
exc = ParsingError(fpname)
|
||||||
@@ -1135,7 +1165,7 @@ class RawConfigParser(MutableMapping):
|
|||||||
sectiondict = self._sections[section]
|
sectiondict = self._sections[section]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
if section != self.default_section:
|
if section != self.default_section:
|
||||||
raise NoSectionError(section)
|
raise NoSectionError(section) from None
|
||||||
# Update with the entry specific variables
|
# Update with the entry specific variables
|
||||||
vardict = {}
|
vardict = {}
|
||||||
if vars:
|
if vars:
|
||||||
@@ -1196,6 +1226,19 @@ class ConfigParser(RawConfigParser):
|
|||||||
self._validate_value_types(section=section)
|
self._validate_value_types(section=section)
|
||||||
super().add_section(section)
|
super().add_section(section)
|
||||||
|
|
||||||
|
def _read_defaults(self, defaults):
|
||||||
|
"""Reads the defaults passed in the initializer, implicitly converting
|
||||||
|
values to strings like the rest of the API.
|
||||||
|
|
||||||
|
Does not perform interpolation for backwards compatibility.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
hold_interpolation = self._interpolation
|
||||||
|
self._interpolation = Interpolation()
|
||||||
|
self.read_dict({self.default_section: defaults})
|
||||||
|
finally:
|
||||||
|
self._interpolation = hold_interpolation
|
||||||
|
|
||||||
|
|
||||||
class SafeConfigParser(ConfigParser):
|
class SafeConfigParser(ConfigParser):
|
||||||
"""ConfigParser alias for backwards compatibility purposes."""
|
"""ConfigParser alias for backwards compatibility purposes."""
|
||||||
@@ -1204,7 +1247,7 @@ class SafeConfigParser(ConfigParser):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"The SafeConfigParser class has been renamed to ConfigParser "
|
"The SafeConfigParser class has been renamed to ConfigParser "
|
||||||
"in Python 3.2. This alias will be removed in future versions."
|
"in Python 3.2. This alias will be removed in Python 3.12."
|
||||||
" Use ConfigParser directly instead.",
|
" Use ConfigParser directly instead.",
|
||||||
DeprecationWarning, stacklevel=2
|
DeprecationWarning, stacklevel=2
|
||||||
)
|
)
|
||||||
|
|||||||
228
Lib/contextlib.py
vendored
228
Lib/contextlib.py
vendored
@@ -1,20 +1,25 @@
|
|||||||
"""Utilities for with-statement contexts. See PEP 343."""
|
"""Utilities for with-statement contexts. See PEP 343."""
|
||||||
import abc
|
import abc
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
import _collections_abc
|
import _collections_abc
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
from types import MethodType, GenericAlias
|
||||||
|
|
||||||
__all__ = ["asynccontextmanager", "contextmanager", "closing", "nullcontext",
|
__all__ = ["asynccontextmanager", "contextmanager", "closing", "nullcontext",
|
||||||
"AbstractContextManager", "AbstractAsyncContextManager",
|
"AbstractContextManager", "AbstractAsyncContextManager",
|
||||||
"AsyncExitStack", "ContextDecorator", "ExitStack",
|
"AsyncExitStack", "ContextDecorator", "ExitStack",
|
||||||
"redirect_stdout", "redirect_stderr", "suppress"]
|
"redirect_stdout", "redirect_stderr", "suppress", "aclosing",
|
||||||
|
"chdir"]
|
||||||
|
|
||||||
|
|
||||||
class AbstractContextManager(abc.ABC):
|
class AbstractContextManager(abc.ABC):
|
||||||
|
|
||||||
"""An abstract base class for context managers."""
|
"""An abstract base class for context managers."""
|
||||||
|
|
||||||
|
__class_getitem__ = classmethod(GenericAlias)
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
"""Return `self` upon entering the runtime context."""
|
"""Return `self` upon entering the runtime context."""
|
||||||
return self
|
return self
|
||||||
@@ -35,6 +40,8 @@ class AbstractAsyncContextManager(abc.ABC):
|
|||||||
|
|
||||||
"""An abstract base class for asynchronous context managers."""
|
"""An abstract base class for asynchronous context managers."""
|
||||||
|
|
||||||
|
__class_getitem__ = classmethod(GenericAlias)
|
||||||
|
|
||||||
async def __aenter__(self):
|
async def __aenter__(self):
|
||||||
"""Return `self` upon entering the runtime context."""
|
"""Return `self` upon entering the runtime context."""
|
||||||
return self
|
return self
|
||||||
@@ -75,6 +82,22 @@ class ContextDecorator(object):
|
|||||||
return inner
|
return inner
|
||||||
|
|
||||||
|
|
||||||
|
class AsyncContextDecorator(object):
|
||||||
|
"A base class or mixin that enables async context managers to work as decorators."
|
||||||
|
|
||||||
|
def _recreate_cm(self):
|
||||||
|
"""Return a recreated instance of self.
|
||||||
|
"""
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __call__(self, func):
|
||||||
|
@wraps(func)
|
||||||
|
async def inner(*args, **kwds):
|
||||||
|
async with self._recreate_cm():
|
||||||
|
return await func(*args, **kwds)
|
||||||
|
return inner
|
||||||
|
|
||||||
|
|
||||||
class _GeneratorContextManagerBase:
|
class _GeneratorContextManagerBase:
|
||||||
"""Shared functionality for @contextmanager and @asynccontextmanager."""
|
"""Shared functionality for @contextmanager and @asynccontextmanager."""
|
||||||
|
|
||||||
@@ -92,18 +115,20 @@ class _GeneratorContextManagerBase:
|
|||||||
# for the class instead.
|
# for the class instead.
|
||||||
# See http://bugs.python.org/issue19404 for more details.
|
# See http://bugs.python.org/issue19404 for more details.
|
||||||
|
|
||||||
|
|
||||||
class _GeneratorContextManager(_GeneratorContextManagerBase,
|
|
||||||
AbstractContextManager,
|
|
||||||
ContextDecorator):
|
|
||||||
"""Helper for @contextmanager decorator."""
|
|
||||||
|
|
||||||
def _recreate_cm(self):
|
def _recreate_cm(self):
|
||||||
# _GCM instances are one-shot context managers, so the
|
# _GCMB instances are one-shot context managers, so the
|
||||||
# CM must be recreated each time a decorated function is
|
# CM must be recreated each time a decorated function is
|
||||||
# called
|
# called
|
||||||
return self.__class__(self.func, self.args, self.kwds)
|
return self.__class__(self.func, self.args, self.kwds)
|
||||||
|
|
||||||
|
|
||||||
|
class _GeneratorContextManager(
|
||||||
|
_GeneratorContextManagerBase,
|
||||||
|
AbstractContextManager,
|
||||||
|
ContextDecorator,
|
||||||
|
):
|
||||||
|
"""Helper for @contextmanager decorator."""
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
# do not keep args and kwds alive unnecessarily
|
# do not keep args and kwds alive unnecessarily
|
||||||
# they are only needed for recreation, which is not possible anymore
|
# they are only needed for recreation, which is not possible anymore
|
||||||
@@ -113,8 +138,8 @@ class _GeneratorContextManager(_GeneratorContextManagerBase,
|
|||||||
except StopIteration:
|
except StopIteration:
|
||||||
raise RuntimeError("generator didn't yield") from None
|
raise RuntimeError("generator didn't yield") from None
|
||||||
|
|
||||||
def __exit__(self, type, value, traceback):
|
def __exit__(self, typ, value, traceback):
|
||||||
if type is None:
|
if typ is None:
|
||||||
try:
|
try:
|
||||||
next(self.gen)
|
next(self.gen)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
@@ -125,9 +150,9 @@ class _GeneratorContextManager(_GeneratorContextManagerBase,
|
|||||||
if value is None:
|
if value is None:
|
||||||
# Need to force instantiation so we can reliably
|
# Need to force instantiation so we can reliably
|
||||||
# tell if we get the same exception back
|
# tell if we get the same exception back
|
||||||
value = type()
|
value = typ()
|
||||||
try:
|
try:
|
||||||
self.gen.throw(type, value, traceback)
|
self.gen.throw(typ, value, traceback)
|
||||||
except StopIteration as exc:
|
except StopIteration as exc:
|
||||||
# Suppress StopIteration *unless* it's the same exception that
|
# Suppress StopIteration *unless* it's the same exception that
|
||||||
# was passed to throw(). This prevents a StopIteration
|
# was passed to throw(). This prevents a StopIteration
|
||||||
@@ -136,75 +161,100 @@ class _GeneratorContextManager(_GeneratorContextManagerBase,
|
|||||||
except RuntimeError as exc:
|
except RuntimeError as exc:
|
||||||
# Don't re-raise the passed in exception. (issue27122)
|
# Don't re-raise the passed in exception. (issue27122)
|
||||||
if exc is value:
|
if exc is value:
|
||||||
|
exc.__traceback__ = traceback
|
||||||
return False
|
return False
|
||||||
# Likewise, avoid suppressing if a StopIteration exception
|
# Avoid suppressing if a StopIteration exception
|
||||||
# was passed to throw() and later wrapped into a RuntimeError
|
# was passed to throw() and later wrapped into a RuntimeError
|
||||||
# (see PEP 479).
|
# (see PEP 479 for sync generators; async generators also
|
||||||
if type is StopIteration and exc.__cause__ is value:
|
# have this behavior). But do this only if the exception wrapped
|
||||||
|
# by the RuntimeError is actually Stop(Async)Iteration (see
|
||||||
|
# issue29692).
|
||||||
|
if (
|
||||||
|
isinstance(value, StopIteration)
|
||||||
|
and exc.__cause__ is value
|
||||||
|
):
|
||||||
|
value.__traceback__ = traceback
|
||||||
return False
|
return False
|
||||||
raise
|
raise
|
||||||
except:
|
except BaseException as exc:
|
||||||
# only re-raise if it's *not* the exception that was
|
# only re-raise if it's *not* the exception that was
|
||||||
# passed to throw(), because __exit__() must not raise
|
# passed to throw(), because __exit__() must not raise
|
||||||
# an exception unless __exit__() itself failed. But throw()
|
# an exception unless __exit__() itself failed. But throw()
|
||||||
# has to raise the exception to signal propagation, so this
|
# has to raise the exception to signal propagation, so this
|
||||||
# fixes the impedance mismatch between the throw() protocol
|
# fixes the impedance mismatch between the throw() protocol
|
||||||
# and the __exit__() protocol.
|
# and the __exit__() protocol.
|
||||||
#
|
if exc is not value:
|
||||||
# This cannot use 'except BaseException as exc' (as in the
|
raise
|
||||||
# async implementation) to maintain compatibility with
|
exc.__traceback__ = traceback
|
||||||
# Python 2, where old-style class exceptions are not caught
|
return False
|
||||||
# by 'except BaseException'.
|
|
||||||
if sys.exc_info()[1] is value:
|
|
||||||
return False
|
|
||||||
raise
|
|
||||||
raise RuntimeError("generator didn't stop after throw()")
|
raise RuntimeError("generator didn't stop after throw()")
|
||||||
|
|
||||||
|
class _AsyncGeneratorContextManager(
|
||||||
class _AsyncGeneratorContextManager(_GeneratorContextManagerBase,
|
_GeneratorContextManagerBase,
|
||||||
AbstractAsyncContextManager):
|
AbstractAsyncContextManager,
|
||||||
"""Helper for @asynccontextmanager."""
|
AsyncContextDecorator,
|
||||||
|
):
|
||||||
|
"""Helper for @asynccontextmanager decorator."""
|
||||||
|
|
||||||
async def __aenter__(self):
|
async def __aenter__(self):
|
||||||
|
# do not keep args and kwds alive unnecessarily
|
||||||
|
# they are only needed for recreation, which is not possible anymore
|
||||||
|
del self.args, self.kwds, self.func
|
||||||
try:
|
try:
|
||||||
return await self.gen.__anext__()
|
return await anext(self.gen)
|
||||||
except StopAsyncIteration:
|
except StopAsyncIteration:
|
||||||
raise RuntimeError("generator didn't yield") from None
|
raise RuntimeError("generator didn't yield") from None
|
||||||
|
|
||||||
async def __aexit__(self, typ, value, traceback):
|
async def __aexit__(self, typ, value, traceback):
|
||||||
if typ is None:
|
if typ is None:
|
||||||
try:
|
try:
|
||||||
await self.gen.__anext__()
|
await anext(self.gen)
|
||||||
except StopAsyncIteration:
|
except StopAsyncIteration:
|
||||||
return
|
return False
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("generator didn't stop")
|
raise RuntimeError("generator didn't stop")
|
||||||
else:
|
else:
|
||||||
if value is None:
|
if value is None:
|
||||||
|
# Need to force instantiation so we can reliably
|
||||||
|
# tell if we get the same exception back
|
||||||
value = typ()
|
value = typ()
|
||||||
# See _GeneratorContextManager.__exit__ for comments on subtleties
|
|
||||||
# in this implementation
|
|
||||||
try:
|
try:
|
||||||
await self.gen.athrow(typ, value, traceback)
|
await self.gen.athrow(typ, value, traceback)
|
||||||
raise RuntimeError("generator didn't stop after throw()")
|
|
||||||
except StopAsyncIteration as exc:
|
except StopAsyncIteration as exc:
|
||||||
|
# Suppress StopIteration *unless* it's the same exception that
|
||||||
|
# was passed to throw(). This prevents a StopIteration
|
||||||
|
# raised inside the "with" statement from being suppressed.
|
||||||
return exc is not value
|
return exc is not value
|
||||||
except RuntimeError as exc:
|
except RuntimeError as exc:
|
||||||
|
# Don't re-raise the passed in exception. (issue27122)
|
||||||
if exc is value:
|
if exc is value:
|
||||||
|
exc.__traceback__ = traceback
|
||||||
return False
|
return False
|
||||||
# Avoid suppressing if a StopIteration exception
|
# Avoid suppressing if a Stop(Async)Iteration exception
|
||||||
# was passed to throw() and later wrapped into a RuntimeError
|
# was passed to athrow() and later wrapped into a RuntimeError
|
||||||
# (see PEP 479 for sync generators; async generators also
|
# (see PEP 479 for sync generators; async generators also
|
||||||
# have this behavior). But do this only if the exception wrapped
|
# have this behavior). But do this only if the exception wrapped
|
||||||
# by the RuntimeError is actully Stop(Async)Iteration (see
|
# by the RuntimeError is actually Stop(Async)Iteration (see
|
||||||
# issue29692).
|
# issue29692).
|
||||||
if isinstance(value, (StopIteration, StopAsyncIteration)):
|
if (
|
||||||
if exc.__cause__ is value:
|
isinstance(value, (StopIteration, StopAsyncIteration))
|
||||||
return False
|
and exc.__cause__ is value
|
||||||
|
):
|
||||||
|
value.__traceback__ = traceback
|
||||||
|
return False
|
||||||
raise
|
raise
|
||||||
except BaseException as exc:
|
except BaseException as exc:
|
||||||
|
# only re-raise if it's *not* the exception that was
|
||||||
|
# passed to throw(), because __exit__() must not raise
|
||||||
|
# an exception unless __exit__() itself failed. But throw()
|
||||||
|
# has to raise the exception to signal propagation, so this
|
||||||
|
# fixes the impedance mismatch between the throw() protocol
|
||||||
|
# and the __exit__() protocol.
|
||||||
if exc is not value:
|
if exc is not value:
|
||||||
raise
|
raise
|
||||||
|
exc.__traceback__ = traceback
|
||||||
|
return False
|
||||||
|
raise RuntimeError("generator didn't stop after athrow()")
|
||||||
|
|
||||||
|
|
||||||
def contextmanager(func):
|
def contextmanager(func):
|
||||||
@@ -298,6 +348,32 @@ class closing(AbstractContextManager):
|
|||||||
self.thing.close()
|
self.thing.close()
|
||||||
|
|
||||||
|
|
||||||
|
class aclosing(AbstractAsyncContextManager):
|
||||||
|
"""Async context manager for safely finalizing an asynchronously cleaned-up
|
||||||
|
resource such as an async generator, calling its ``aclose()`` method.
|
||||||
|
|
||||||
|
Code like this:
|
||||||
|
|
||||||
|
async with aclosing(<module>.fetch(<arguments>)) as agen:
|
||||||
|
<block>
|
||||||
|
|
||||||
|
is equivalent to this:
|
||||||
|
|
||||||
|
agen = <module>.fetch(<arguments>)
|
||||||
|
try:
|
||||||
|
<block>
|
||||||
|
finally:
|
||||||
|
await agen.aclose()
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, thing):
|
||||||
|
self.thing = thing
|
||||||
|
async def __aenter__(self):
|
||||||
|
return self.thing
|
||||||
|
async def __aexit__(self, *exc_info):
|
||||||
|
await self.thing.aclose()
|
||||||
|
|
||||||
|
|
||||||
class _RedirectStream(AbstractContextManager):
|
class _RedirectStream(AbstractContextManager):
|
||||||
|
|
||||||
_stream = None
|
_stream = None
|
||||||
@@ -373,12 +449,10 @@ class _BaseExitStack:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _create_exit_wrapper(cm, cm_exit):
|
def _create_exit_wrapper(cm, cm_exit):
|
||||||
def _exit_wrapper(exc_type, exc, tb):
|
return MethodType(cm_exit, cm)
|
||||||
return cm_exit(cm, exc_type, exc, tb)
|
|
||||||
return _exit_wrapper
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _create_cb_wrapper(callback, *args, **kwds):
|
def _create_cb_wrapper(callback, /, *args, **kwds):
|
||||||
def _exit_wrapper(exc_type, exc, tb):
|
def _exit_wrapper(exc_type, exc, tb):
|
||||||
callback(*args, **kwds)
|
callback(*args, **kwds)
|
||||||
return _exit_wrapper
|
return _exit_wrapper
|
||||||
@@ -421,13 +495,18 @@ class _BaseExitStack:
|
|||||||
"""
|
"""
|
||||||
# We look up the special methods on the type to match the with
|
# We look up the special methods on the type to match the with
|
||||||
# statement.
|
# statement.
|
||||||
_cm_type = type(cm)
|
cls = type(cm)
|
||||||
_exit = _cm_type.__exit__
|
try:
|
||||||
result = _cm_type.__enter__(cm)
|
_enter = cls.__enter__
|
||||||
|
_exit = cls.__exit__
|
||||||
|
except AttributeError:
|
||||||
|
raise TypeError(f"'{cls.__module__}.{cls.__qualname__}' object does "
|
||||||
|
f"not support the context manager protocol") from None
|
||||||
|
result = _enter(cm)
|
||||||
self._push_cm_exit(cm, _exit)
|
self._push_cm_exit(cm, _exit)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def callback(self, callback, *args, **kwds):
|
def callback(self, callback, /, *args, **kwds):
|
||||||
"""Registers an arbitrary callback and arguments.
|
"""Registers an arbitrary callback and arguments.
|
||||||
|
|
||||||
Cannot suppress exceptions.
|
Cannot suppress exceptions.
|
||||||
@@ -443,7 +522,6 @@ class _BaseExitStack:
|
|||||||
def _push_cm_exit(self, cm, cm_exit):
|
def _push_cm_exit(self, cm, cm_exit):
|
||||||
"""Helper to correctly register callbacks to __exit__ methods."""
|
"""Helper to correctly register callbacks to __exit__ methods."""
|
||||||
_exit_wrapper = self._create_exit_wrapper(cm, cm_exit)
|
_exit_wrapper = self._create_exit_wrapper(cm, cm_exit)
|
||||||
_exit_wrapper.__self__ = cm
|
|
||||||
self._push_exit_callback(_exit_wrapper, True)
|
self._push_exit_callback(_exit_wrapper, True)
|
||||||
|
|
||||||
def _push_exit_callback(self, callback, is_sync=True):
|
def _push_exit_callback(self, callback, is_sync=True):
|
||||||
@@ -475,10 +553,10 @@ class ExitStack(_BaseExitStack, AbstractContextManager):
|
|||||||
# Context may not be correct, so find the end of the chain
|
# Context may not be correct, so find the end of the chain
|
||||||
while 1:
|
while 1:
|
||||||
exc_context = new_exc.__context__
|
exc_context = new_exc.__context__
|
||||||
if exc_context is old_exc:
|
if exc_context is None or exc_context is old_exc:
|
||||||
# Context is already set correctly (see issue 20317)
|
# Context is already set correctly (see issue 20317)
|
||||||
return
|
return
|
||||||
if exc_context is None or exc_context is frame_exc:
|
if exc_context is frame_exc:
|
||||||
break
|
break
|
||||||
new_exc = exc_context
|
new_exc = exc_context
|
||||||
# Change the end of the chain to point to the exception
|
# Change the end of the chain to point to the exception
|
||||||
@@ -535,12 +613,10 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _create_async_exit_wrapper(cm, cm_exit):
|
def _create_async_exit_wrapper(cm, cm_exit):
|
||||||
async def _exit_wrapper(exc_type, exc, tb):
|
return MethodType(cm_exit, cm)
|
||||||
return await cm_exit(cm, exc_type, exc, tb)
|
|
||||||
return _exit_wrapper
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _create_async_cb_wrapper(callback, *args, **kwds):
|
def _create_async_cb_wrapper(callback, /, *args, **kwds):
|
||||||
async def _exit_wrapper(exc_type, exc, tb):
|
async def _exit_wrapper(exc_type, exc, tb):
|
||||||
await callback(*args, **kwds)
|
await callback(*args, **kwds)
|
||||||
return _exit_wrapper
|
return _exit_wrapper
|
||||||
@@ -551,9 +627,15 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager):
|
|||||||
If successful, also pushes its __aexit__ method as a callback and
|
If successful, also pushes its __aexit__ method as a callback and
|
||||||
returns the result of the __aenter__ method.
|
returns the result of the __aenter__ method.
|
||||||
"""
|
"""
|
||||||
_cm_type = type(cm)
|
cls = type(cm)
|
||||||
_exit = _cm_type.__aexit__
|
try:
|
||||||
result = await _cm_type.__aenter__(cm)
|
_enter = cls.__aenter__
|
||||||
|
_exit = cls.__aexit__
|
||||||
|
except AttributeError:
|
||||||
|
raise TypeError(f"'{cls.__module__}.{cls.__qualname__}' object does "
|
||||||
|
f"not support the asynchronous context manager protocol"
|
||||||
|
) from None
|
||||||
|
result = await _enter(cm)
|
||||||
self._push_async_cm_exit(cm, _exit)
|
self._push_async_cm_exit(cm, _exit)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@@ -575,7 +657,7 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager):
|
|||||||
self._push_async_cm_exit(exit, exit_method)
|
self._push_async_cm_exit(exit, exit_method)
|
||||||
return exit # Allow use as a decorator
|
return exit # Allow use as a decorator
|
||||||
|
|
||||||
def push_async_callback(self, callback, *args, **kwds):
|
def push_async_callback(self, callback, /, *args, **kwds):
|
||||||
"""Registers an arbitrary coroutine function and arguments.
|
"""Registers an arbitrary coroutine function and arguments.
|
||||||
|
|
||||||
Cannot suppress exceptions.
|
Cannot suppress exceptions.
|
||||||
@@ -596,7 +678,6 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager):
|
|||||||
"""Helper to correctly register coroutine function to __aexit__
|
"""Helper to correctly register coroutine function to __aexit__
|
||||||
method."""
|
method."""
|
||||||
_exit_wrapper = self._create_async_exit_wrapper(cm, cm_exit)
|
_exit_wrapper = self._create_async_exit_wrapper(cm, cm_exit)
|
||||||
_exit_wrapper.__self__ = cm
|
|
||||||
self._push_exit_callback(_exit_wrapper, False)
|
self._push_exit_callback(_exit_wrapper, False)
|
||||||
|
|
||||||
async def __aenter__(self):
|
async def __aenter__(self):
|
||||||
@@ -612,10 +693,10 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager):
|
|||||||
# Context may not be correct, so find the end of the chain
|
# Context may not be correct, so find the end of the chain
|
||||||
while 1:
|
while 1:
|
||||||
exc_context = new_exc.__context__
|
exc_context = new_exc.__context__
|
||||||
if exc_context is old_exc:
|
if exc_context is None or exc_context is old_exc:
|
||||||
# Context is already set correctly (see issue 20317)
|
# Context is already set correctly (see issue 20317)
|
||||||
return
|
return
|
||||||
if exc_context is None or exc_context is frame_exc:
|
if exc_context is frame_exc:
|
||||||
break
|
break
|
||||||
new_exc = exc_context
|
new_exc = exc_context
|
||||||
# Change the end of the chain to point to the exception
|
# Change the end of the chain to point to the exception
|
||||||
@@ -656,7 +737,7 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager):
|
|||||||
return received_exc and suppressed_exc
|
return received_exc and suppressed_exc
|
||||||
|
|
||||||
|
|
||||||
class nullcontext(AbstractContextManager):
|
class nullcontext(AbstractContextManager, AbstractAsyncContextManager):
|
||||||
"""Context manager that does no additional processing.
|
"""Context manager that does no additional processing.
|
||||||
|
|
||||||
Used as a stand-in for a normal context manager, when a particular
|
Used as a stand-in for a normal context manager, when a particular
|
||||||
@@ -675,3 +756,24 @@ class nullcontext(AbstractContextManager):
|
|||||||
|
|
||||||
def __exit__(self, *excinfo):
|
def __exit__(self, *excinfo):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
async def __aenter__(self):
|
||||||
|
return self.enter_result
|
||||||
|
|
||||||
|
async def __aexit__(self, *excinfo):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class chdir(AbstractContextManager):
|
||||||
|
"""Non thread-safe context manager to change the current working directory."""
|
||||||
|
|
||||||
|
def __init__(self, path):
|
||||||
|
self.path = path
|
||||||
|
self._old_cwd = []
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self._old_cwd.append(os.getcwd())
|
||||||
|
os.chdir(self.path)
|
||||||
|
|
||||||
|
def __exit__(self, *excinfo):
|
||||||
|
os.chdir(self._old_cwd.pop())
|
||||||
|
|||||||
7
Lib/copy.py
vendored
7
Lib/copy.py
vendored
@@ -39,8 +39,8 @@ Python's deep copy operation avoids these problems by:
|
|||||||
set of components copied
|
set of components copied
|
||||||
|
|
||||||
This version does not copy types like module, class, function, method,
|
This version does not copy types like module, class, function, method,
|
||||||
nor stack trace, stack frame, nor file, socket, window, nor array, nor
|
nor stack trace, stack frame, nor file, socket, window, nor any
|
||||||
any similar types.
|
similar types.
|
||||||
|
|
||||||
Classes can use the same interfaces to control copying that they use
|
Classes can use the same interfaces to control copying that they use
|
||||||
to control pickling: they can define methods called __getinitargs__(),
|
to control pickling: they can define methods called __getinitargs__(),
|
||||||
@@ -192,6 +192,7 @@ d[bytes] = _deepcopy_atomic
|
|||||||
d[str] = _deepcopy_atomic
|
d[str] = _deepcopy_atomic
|
||||||
d[types.CodeType] = _deepcopy_atomic
|
d[types.CodeType] = _deepcopy_atomic
|
||||||
d[type] = _deepcopy_atomic
|
d[type] = _deepcopy_atomic
|
||||||
|
d[range] = _deepcopy_atomic
|
||||||
d[types.BuiltinFunctionType] = _deepcopy_atomic
|
d[types.BuiltinFunctionType] = _deepcopy_atomic
|
||||||
d[types.FunctionType] = _deepcopy_atomic
|
d[types.FunctionType] = _deepcopy_atomic
|
||||||
d[weakref.ref] = _deepcopy_atomic
|
d[weakref.ref] = _deepcopy_atomic
|
||||||
@@ -257,7 +258,7 @@ def _keep_alive(x, memo):
|
|||||||
|
|
||||||
def _reconstruct(x, memo, func, args,
|
def _reconstruct(x, memo, func, args,
|
||||||
state=None, listiter=None, dictiter=None,
|
state=None, listiter=None, dictiter=None,
|
||||||
deepcopy=deepcopy):
|
*, deepcopy=deepcopy):
|
||||||
deep = memo is not None
|
deep = memo is not None
|
||||||
if deep and args:
|
if deep and args:
|
||||||
args = (deepcopy(arg, memo) for arg in args)
|
args = (deepcopy(arg, memo) for arg in args)
|
||||||
|
|||||||
577
Lib/ctypes/__init__.py
vendored
Normal file
577
Lib/ctypes/__init__.py
vendored
Normal file
@@ -0,0 +1,577 @@
|
|||||||
|
"""create and manipulate C data types in Python"""
|
||||||
|
|
||||||
|
import os as _os, sys as _sys
|
||||||
|
import types as _types
|
||||||
|
|
||||||
|
__version__ = "1.1.0"
|
||||||
|
|
||||||
|
from _ctypes import Union, Structure, Array
|
||||||
|
from _ctypes import _Pointer
|
||||||
|
from _ctypes import CFuncPtr as _CFuncPtr
|
||||||
|
from _ctypes import __version__ as _ctypes_version
|
||||||
|
from _ctypes import RTLD_LOCAL, RTLD_GLOBAL
|
||||||
|
from _ctypes import ArgumentError
|
||||||
|
from _ctypes import SIZEOF_TIME_T
|
||||||
|
|
||||||
|
from struct import calcsize as _calcsize
|
||||||
|
|
||||||
|
if __version__ != _ctypes_version:
|
||||||
|
raise Exception("Version number mismatch", __version__, _ctypes_version)
|
||||||
|
|
||||||
|
if _os.name == "nt":
|
||||||
|
from _ctypes import FormatError
|
||||||
|
|
||||||
|
DEFAULT_MODE = RTLD_LOCAL
|
||||||
|
if _os.name == "posix" and _sys.platform == "darwin":
|
||||||
|
# On OS X 10.3, we use RTLD_GLOBAL as default mode
|
||||||
|
# because RTLD_LOCAL does not work at least on some
|
||||||
|
# libraries. OS X 10.3 is Darwin 7, so we check for
|
||||||
|
# that.
|
||||||
|
|
||||||
|
if int(_os.uname().release.split('.')[0]) < 8:
|
||||||
|
DEFAULT_MODE = RTLD_GLOBAL
|
||||||
|
|
||||||
|
from _ctypes import FUNCFLAG_CDECL as _FUNCFLAG_CDECL, \
|
||||||
|
FUNCFLAG_PYTHONAPI as _FUNCFLAG_PYTHONAPI, \
|
||||||
|
FUNCFLAG_USE_ERRNO as _FUNCFLAG_USE_ERRNO, \
|
||||||
|
FUNCFLAG_USE_LASTERROR as _FUNCFLAG_USE_LASTERROR
|
||||||
|
|
||||||
|
# WINOLEAPI -> HRESULT
|
||||||
|
# WINOLEAPI_(type)
|
||||||
|
#
|
||||||
|
# STDMETHODCALLTYPE
|
||||||
|
#
|
||||||
|
# STDMETHOD(name)
|
||||||
|
# STDMETHOD_(type, name)
|
||||||
|
#
|
||||||
|
# STDAPICALLTYPE
|
||||||
|
|
||||||
|
def create_string_buffer(init, size=None):
|
||||||
|
"""create_string_buffer(aBytes) -> character array
|
||||||
|
create_string_buffer(anInteger) -> character array
|
||||||
|
create_string_buffer(aBytes, anInteger) -> character array
|
||||||
|
"""
|
||||||
|
if isinstance(init, bytes):
|
||||||
|
if size is None:
|
||||||
|
size = len(init)+1
|
||||||
|
_sys.audit("ctypes.create_string_buffer", init, size)
|
||||||
|
buftype = c_char * size
|
||||||
|
buf = buftype()
|
||||||
|
buf.value = init
|
||||||
|
return buf
|
||||||
|
elif isinstance(init, int):
|
||||||
|
_sys.audit("ctypes.create_string_buffer", None, init)
|
||||||
|
buftype = c_char * init
|
||||||
|
buf = buftype()
|
||||||
|
return buf
|
||||||
|
raise TypeError(init)
|
||||||
|
|
||||||
|
# Alias to create_string_buffer() for backward compatibility
|
||||||
|
c_buffer = create_string_buffer
|
||||||
|
|
||||||
|
_c_functype_cache = {}
|
||||||
|
def CFUNCTYPE(restype, *argtypes, **kw):
|
||||||
|
"""CFUNCTYPE(restype, *argtypes,
|
||||||
|
use_errno=False, use_last_error=False) -> function prototype.
|
||||||
|
|
||||||
|
restype: the result type
|
||||||
|
argtypes: a sequence specifying the argument types
|
||||||
|
|
||||||
|
The function prototype can be called in different ways to create a
|
||||||
|
callable object:
|
||||||
|
|
||||||
|
prototype(integer address) -> foreign function
|
||||||
|
prototype(callable) -> create and return a C callable function from callable
|
||||||
|
prototype(integer index, method name[, paramflags]) -> foreign function calling a COM method
|
||||||
|
prototype((ordinal number, dll object)[, paramflags]) -> foreign function exported by ordinal
|
||||||
|
prototype((function name, dll object)[, paramflags]) -> foreign function exported by name
|
||||||
|
"""
|
||||||
|
flags = _FUNCFLAG_CDECL
|
||||||
|
if kw.pop("use_errno", False):
|
||||||
|
flags |= _FUNCFLAG_USE_ERRNO
|
||||||
|
if kw.pop("use_last_error", False):
|
||||||
|
flags |= _FUNCFLAG_USE_LASTERROR
|
||||||
|
if kw:
|
||||||
|
raise ValueError("unexpected keyword argument(s) %s" % kw.keys())
|
||||||
|
|
||||||
|
try:
|
||||||
|
return _c_functype_cache[(restype, argtypes, flags)]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class CFunctionType(_CFuncPtr):
|
||||||
|
_argtypes_ = argtypes
|
||||||
|
_restype_ = restype
|
||||||
|
_flags_ = flags
|
||||||
|
_c_functype_cache[(restype, argtypes, flags)] = CFunctionType
|
||||||
|
return CFunctionType
|
||||||
|
|
||||||
|
if _os.name == "nt":
|
||||||
|
from _ctypes import LoadLibrary as _dlopen
|
||||||
|
from _ctypes import FUNCFLAG_STDCALL as _FUNCFLAG_STDCALL
|
||||||
|
|
||||||
|
_win_functype_cache = {}
|
||||||
|
def WINFUNCTYPE(restype, *argtypes, **kw):
|
||||||
|
# docstring set later (very similar to CFUNCTYPE.__doc__)
|
||||||
|
flags = _FUNCFLAG_STDCALL
|
||||||
|
if kw.pop("use_errno", False):
|
||||||
|
flags |= _FUNCFLAG_USE_ERRNO
|
||||||
|
if kw.pop("use_last_error", False):
|
||||||
|
flags |= _FUNCFLAG_USE_LASTERROR
|
||||||
|
if kw:
|
||||||
|
raise ValueError("unexpected keyword argument(s) %s" % kw.keys())
|
||||||
|
|
||||||
|
try:
|
||||||
|
return _win_functype_cache[(restype, argtypes, flags)]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class WinFunctionType(_CFuncPtr):
|
||||||
|
_argtypes_ = argtypes
|
||||||
|
_restype_ = restype
|
||||||
|
_flags_ = flags
|
||||||
|
_win_functype_cache[(restype, argtypes, flags)] = WinFunctionType
|
||||||
|
return WinFunctionType
|
||||||
|
if WINFUNCTYPE.__doc__:
|
||||||
|
WINFUNCTYPE.__doc__ = CFUNCTYPE.__doc__.replace("CFUNCTYPE", "WINFUNCTYPE")
|
||||||
|
|
||||||
|
elif _os.name == "posix":
|
||||||
|
from _ctypes import dlopen as _dlopen
|
||||||
|
|
||||||
|
from _ctypes import sizeof, byref, addressof, alignment, resize
|
||||||
|
from _ctypes import get_errno, set_errno
|
||||||
|
from _ctypes import _SimpleCData
|
||||||
|
|
||||||
|
def _check_size(typ, typecode=None):
|
||||||
|
# Check if sizeof(ctypes_type) against struct.calcsize. This
|
||||||
|
# should protect somewhat against a misconfigured libffi.
|
||||||
|
from struct import calcsize
|
||||||
|
if typecode is None:
|
||||||
|
# Most _type_ codes are the same as used in struct
|
||||||
|
typecode = typ._type_
|
||||||
|
actual, required = sizeof(typ), calcsize(typecode)
|
||||||
|
if actual != required:
|
||||||
|
raise SystemError("sizeof(%s) wrong: %d instead of %d" % \
|
||||||
|
(typ, actual, required))
|
||||||
|
|
||||||
|
class py_object(_SimpleCData):
|
||||||
|
_type_ = "O"
|
||||||
|
def __repr__(self):
|
||||||
|
try:
|
||||||
|
return super().__repr__()
|
||||||
|
except ValueError:
|
||||||
|
return "%s(<NULL>)" % type(self).__name__
|
||||||
|
_check_size(py_object, "P")
|
||||||
|
|
||||||
|
class c_short(_SimpleCData):
|
||||||
|
_type_ = "h"
|
||||||
|
_check_size(c_short)
|
||||||
|
|
||||||
|
class c_ushort(_SimpleCData):
|
||||||
|
_type_ = "H"
|
||||||
|
_check_size(c_ushort)
|
||||||
|
|
||||||
|
class c_long(_SimpleCData):
|
||||||
|
_type_ = "l"
|
||||||
|
_check_size(c_long)
|
||||||
|
|
||||||
|
class c_ulong(_SimpleCData):
|
||||||
|
_type_ = "L"
|
||||||
|
_check_size(c_ulong)
|
||||||
|
|
||||||
|
if _calcsize("i") == _calcsize("l"):
|
||||||
|
# if int and long have the same size, make c_int an alias for c_long
|
||||||
|
c_int = c_long
|
||||||
|
c_uint = c_ulong
|
||||||
|
else:
|
||||||
|
class c_int(_SimpleCData):
|
||||||
|
_type_ = "i"
|
||||||
|
_check_size(c_int)
|
||||||
|
|
||||||
|
class c_uint(_SimpleCData):
|
||||||
|
_type_ = "I"
|
||||||
|
_check_size(c_uint)
|
||||||
|
|
||||||
|
class c_float(_SimpleCData):
|
||||||
|
_type_ = "f"
|
||||||
|
_check_size(c_float)
|
||||||
|
|
||||||
|
class c_double(_SimpleCData):
|
||||||
|
_type_ = "d"
|
||||||
|
_check_size(c_double)
|
||||||
|
|
||||||
|
class c_longdouble(_SimpleCData):
|
||||||
|
_type_ = "g"
|
||||||
|
if sizeof(c_longdouble) == sizeof(c_double):
|
||||||
|
c_longdouble = c_double
|
||||||
|
|
||||||
|
if _calcsize("l") == _calcsize("q"):
|
||||||
|
# if long and long long have the same size, make c_longlong an alias for c_long
|
||||||
|
c_longlong = c_long
|
||||||
|
c_ulonglong = c_ulong
|
||||||
|
else:
|
||||||
|
class c_longlong(_SimpleCData):
|
||||||
|
_type_ = "q"
|
||||||
|
_check_size(c_longlong)
|
||||||
|
|
||||||
|
class c_ulonglong(_SimpleCData):
|
||||||
|
_type_ = "Q"
|
||||||
|
## def from_param(cls, val):
|
||||||
|
## return ('d', float(val), val)
|
||||||
|
## from_param = classmethod(from_param)
|
||||||
|
_check_size(c_ulonglong)
|
||||||
|
|
||||||
|
class c_ubyte(_SimpleCData):
|
||||||
|
_type_ = "B"
|
||||||
|
c_ubyte.__ctype_le__ = c_ubyte.__ctype_be__ = c_ubyte
|
||||||
|
# backward compatibility:
|
||||||
|
##c_uchar = c_ubyte
|
||||||
|
_check_size(c_ubyte)
|
||||||
|
|
||||||
|
class c_byte(_SimpleCData):
|
||||||
|
_type_ = "b"
|
||||||
|
c_byte.__ctype_le__ = c_byte.__ctype_be__ = c_byte
|
||||||
|
_check_size(c_byte)
|
||||||
|
|
||||||
|
class c_char(_SimpleCData):
|
||||||
|
_type_ = "c"
|
||||||
|
c_char.__ctype_le__ = c_char.__ctype_be__ = c_char
|
||||||
|
_check_size(c_char)
|
||||||
|
|
||||||
|
class c_char_p(_SimpleCData):
|
||||||
|
_type_ = "z"
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s(%s)" % (self.__class__.__name__, c_void_p.from_buffer(self).value)
|
||||||
|
_check_size(c_char_p, "P")
|
||||||
|
|
||||||
|
class c_void_p(_SimpleCData):
|
||||||
|
_type_ = "P"
|
||||||
|
c_voidp = c_void_p # backwards compatibility (to a bug)
|
||||||
|
_check_size(c_void_p)
|
||||||
|
|
||||||
|
class c_bool(_SimpleCData):
|
||||||
|
_type_ = "?"
|
||||||
|
|
||||||
|
from _ctypes import POINTER, pointer, _pointer_type_cache
|
||||||
|
|
||||||
|
class c_wchar_p(_SimpleCData):
|
||||||
|
_type_ = "Z"
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s(%s)" % (self.__class__.__name__, c_void_p.from_buffer(self).value)
|
||||||
|
|
||||||
|
class c_wchar(_SimpleCData):
|
||||||
|
_type_ = "u"
|
||||||
|
|
||||||
|
def _reset_cache():
|
||||||
|
_pointer_type_cache.clear()
|
||||||
|
_c_functype_cache.clear()
|
||||||
|
if _os.name == "nt":
|
||||||
|
_win_functype_cache.clear()
|
||||||
|
# _SimpleCData.c_wchar_p_from_param
|
||||||
|
POINTER(c_wchar).from_param = c_wchar_p.from_param
|
||||||
|
# _SimpleCData.c_char_p_from_param
|
||||||
|
POINTER(c_char).from_param = c_char_p.from_param
|
||||||
|
_pointer_type_cache[None] = c_void_p
|
||||||
|
|
||||||
|
def create_unicode_buffer(init, size=None):
|
||||||
|
"""create_unicode_buffer(aString) -> character array
|
||||||
|
create_unicode_buffer(anInteger) -> character array
|
||||||
|
create_unicode_buffer(aString, anInteger) -> character array
|
||||||
|
"""
|
||||||
|
if isinstance(init, str):
|
||||||
|
if size is None:
|
||||||
|
if sizeof(c_wchar) == 2:
|
||||||
|
# UTF-16 requires a surrogate pair (2 wchar_t) for non-BMP
|
||||||
|
# characters (outside [U+0000; U+FFFF] range). +1 for trailing
|
||||||
|
# NUL character.
|
||||||
|
size = sum(2 if ord(c) > 0xFFFF else 1 for c in init) + 1
|
||||||
|
else:
|
||||||
|
# 32-bit wchar_t (1 wchar_t per Unicode character). +1 for
|
||||||
|
# trailing NUL character.
|
||||||
|
size = len(init) + 1
|
||||||
|
_sys.audit("ctypes.create_unicode_buffer", init, size)
|
||||||
|
buftype = c_wchar * size
|
||||||
|
buf = buftype()
|
||||||
|
buf.value = init
|
||||||
|
return buf
|
||||||
|
elif isinstance(init, int):
|
||||||
|
_sys.audit("ctypes.create_unicode_buffer", None, init)
|
||||||
|
buftype = c_wchar * init
|
||||||
|
buf = buftype()
|
||||||
|
return buf
|
||||||
|
raise TypeError(init)
|
||||||
|
|
||||||
|
|
||||||
|
# XXX Deprecated
|
||||||
|
def SetPointerType(pointer, cls):
|
||||||
|
if _pointer_type_cache.get(cls, None) is not None:
|
||||||
|
raise RuntimeError("This type already exists in the cache")
|
||||||
|
if id(pointer) not in _pointer_type_cache:
|
||||||
|
raise RuntimeError("What's this???")
|
||||||
|
pointer.set_type(cls)
|
||||||
|
_pointer_type_cache[cls] = pointer
|
||||||
|
del _pointer_type_cache[id(pointer)]
|
||||||
|
|
||||||
|
# XXX Deprecated
|
||||||
|
def ARRAY(typ, len):
|
||||||
|
return typ * len
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
|
||||||
|
class CDLL(object):
|
||||||
|
"""An instance of this class represents a loaded dll/shared
|
||||||
|
library, exporting functions using the standard C calling
|
||||||
|
convention (named 'cdecl' on Windows).
|
||||||
|
|
||||||
|
The exported functions can be accessed as attributes, or by
|
||||||
|
indexing with the function name. Examples:
|
||||||
|
|
||||||
|
<obj>.qsort -> callable object
|
||||||
|
<obj>['qsort'] -> callable object
|
||||||
|
|
||||||
|
Calling the functions releases the Python GIL during the call and
|
||||||
|
reacquires it afterwards.
|
||||||
|
"""
|
||||||
|
_func_flags_ = _FUNCFLAG_CDECL
|
||||||
|
_func_restype_ = c_int
|
||||||
|
# default values for repr
|
||||||
|
_name = '<uninitialized>'
|
||||||
|
_handle = 0
|
||||||
|
_FuncPtr = None
|
||||||
|
|
||||||
|
def __init__(self, name, mode=DEFAULT_MODE, handle=None,
|
||||||
|
use_errno=False,
|
||||||
|
use_last_error=False,
|
||||||
|
winmode=None):
|
||||||
|
self._name = name
|
||||||
|
flags = self._func_flags_
|
||||||
|
if use_errno:
|
||||||
|
flags |= _FUNCFLAG_USE_ERRNO
|
||||||
|
if use_last_error:
|
||||||
|
flags |= _FUNCFLAG_USE_LASTERROR
|
||||||
|
if _sys.platform.startswith("aix"):
|
||||||
|
"""When the name contains ".a(" and ends with ")",
|
||||||
|
e.g., "libFOO.a(libFOO.so)" - this is taken to be an
|
||||||
|
archive(member) syntax for dlopen(), and the mode is adjusted.
|
||||||
|
Otherwise, name is presented to dlopen() as a file argument.
|
||||||
|
"""
|
||||||
|
if name and name.endswith(")") and ".a(" in name:
|
||||||
|
mode |= ( _os.RTLD_MEMBER | _os.RTLD_NOW )
|
||||||
|
if _os.name == "nt":
|
||||||
|
if winmode is not None:
|
||||||
|
mode = winmode
|
||||||
|
else:
|
||||||
|
import nt
|
||||||
|
mode = nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
|
||||||
|
if '/' in name or '\\' in name:
|
||||||
|
self._name = nt._getfullpathname(self._name)
|
||||||
|
mode |= nt._LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
|
||||||
|
|
||||||
|
class _FuncPtr(_CFuncPtr):
|
||||||
|
_flags_ = flags
|
||||||
|
_restype_ = self._func_restype_
|
||||||
|
self._FuncPtr = _FuncPtr
|
||||||
|
|
||||||
|
if handle is None:
|
||||||
|
self._handle = _dlopen(self._name, mode)
|
||||||
|
else:
|
||||||
|
self._handle = handle
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<%s '%s', handle %x at %#x>" % \
|
||||||
|
(self.__class__.__name__, self._name,
|
||||||
|
(self._handle & (_sys.maxsize*2 + 1)),
|
||||||
|
id(self) & (_sys.maxsize*2 + 1))
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
if name.startswith('__') and name.endswith('__'):
|
||||||
|
raise AttributeError(name)
|
||||||
|
func = self.__getitem__(name)
|
||||||
|
setattr(self, name, func)
|
||||||
|
return func
|
||||||
|
|
||||||
|
def __getitem__(self, name_or_ordinal):
|
||||||
|
func = self._FuncPtr((name_or_ordinal, self))
|
||||||
|
if not isinstance(name_or_ordinal, int):
|
||||||
|
func.__name__ = name_or_ordinal
|
||||||
|
return func
|
||||||
|
|
||||||
|
class PyDLL(CDLL):
|
||||||
|
"""This class represents the Python library itself. It allows
|
||||||
|
accessing Python API functions. The GIL is not released, and
|
||||||
|
Python exceptions are handled correctly.
|
||||||
|
"""
|
||||||
|
_func_flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
|
||||||
|
|
||||||
|
if _os.name == "nt":
|
||||||
|
|
||||||
|
class WinDLL(CDLL):
|
||||||
|
"""This class represents a dll exporting functions using the
|
||||||
|
Windows stdcall calling convention.
|
||||||
|
"""
|
||||||
|
_func_flags_ = _FUNCFLAG_STDCALL
|
||||||
|
|
||||||
|
# XXX Hm, what about HRESULT as normal parameter?
|
||||||
|
# Mustn't it derive from c_long then?
|
||||||
|
from _ctypes import _check_HRESULT, _SimpleCData
|
||||||
|
class HRESULT(_SimpleCData):
|
||||||
|
_type_ = "l"
|
||||||
|
# _check_retval_ is called with the function's result when it
|
||||||
|
# is used as restype. It checks for the FAILED bit, and
|
||||||
|
# raises an OSError if it is set.
|
||||||
|
#
|
||||||
|
# The _check_retval_ method is implemented in C, so that the
|
||||||
|
# method definition itself is not included in the traceback
|
||||||
|
# when it raises an error - that is what we want (and Python
|
||||||
|
# doesn't have a way to raise an exception in the caller's
|
||||||
|
# frame).
|
||||||
|
_check_retval_ = _check_HRESULT
|
||||||
|
|
||||||
|
class OleDLL(CDLL):
|
||||||
|
"""This class represents a dll exporting functions using the
|
||||||
|
Windows stdcall calling convention, and returning HRESULT.
|
||||||
|
HRESULT error values are automatically raised as OSError
|
||||||
|
exceptions.
|
||||||
|
"""
|
||||||
|
_func_flags_ = _FUNCFLAG_STDCALL
|
||||||
|
_func_restype_ = HRESULT
|
||||||
|
|
||||||
|
class LibraryLoader(object):
|
||||||
|
def __init__(self, dlltype):
|
||||||
|
self._dlltype = dlltype
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
if name[0] == '_':
|
||||||
|
raise AttributeError(name)
|
||||||
|
try:
|
||||||
|
dll = self._dlltype(name)
|
||||||
|
except OSError:
|
||||||
|
raise AttributeError(name)
|
||||||
|
setattr(self, name, dll)
|
||||||
|
return dll
|
||||||
|
|
||||||
|
def __getitem__(self, name):
|
||||||
|
return getattr(self, name)
|
||||||
|
|
||||||
|
def LoadLibrary(self, name):
|
||||||
|
return self._dlltype(name)
|
||||||
|
|
||||||
|
__class_getitem__ = classmethod(_types.GenericAlias)
|
||||||
|
|
||||||
|
cdll = LibraryLoader(CDLL)
|
||||||
|
pydll = LibraryLoader(PyDLL)
|
||||||
|
|
||||||
|
if _os.name == "nt":
|
||||||
|
pythonapi = PyDLL("python dll", None, _sys.dllhandle)
|
||||||
|
elif _sys.platform == "cygwin":
|
||||||
|
pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2])
|
||||||
|
else:
|
||||||
|
pythonapi = PyDLL(None)
|
||||||
|
|
||||||
|
|
||||||
|
if _os.name == "nt":
|
||||||
|
windll = LibraryLoader(WinDLL)
|
||||||
|
oledll = LibraryLoader(OleDLL)
|
||||||
|
|
||||||
|
GetLastError = windll.kernel32.GetLastError
|
||||||
|
from _ctypes import get_last_error, set_last_error
|
||||||
|
|
||||||
|
def WinError(code=None, descr=None):
|
||||||
|
if code is None:
|
||||||
|
code = GetLastError()
|
||||||
|
if descr is None:
|
||||||
|
descr = FormatError(code).strip()
|
||||||
|
return OSError(None, descr, None, code)
|
||||||
|
|
||||||
|
if sizeof(c_uint) == sizeof(c_void_p):
|
||||||
|
c_size_t = c_uint
|
||||||
|
c_ssize_t = c_int
|
||||||
|
elif sizeof(c_ulong) == sizeof(c_void_p):
|
||||||
|
c_size_t = c_ulong
|
||||||
|
c_ssize_t = c_long
|
||||||
|
elif sizeof(c_ulonglong) == sizeof(c_void_p):
|
||||||
|
c_size_t = c_ulonglong
|
||||||
|
c_ssize_t = c_longlong
|
||||||
|
|
||||||
|
# functions
|
||||||
|
|
||||||
|
from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, _cast_addr
|
||||||
|
|
||||||
|
## void *memmove(void *, const void *, size_t);
|
||||||
|
memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr)
|
||||||
|
|
||||||
|
## void *memset(void *, int, size_t)
|
||||||
|
memset = CFUNCTYPE(c_void_p, c_void_p, c_int, c_size_t)(_memset_addr)
|
||||||
|
|
||||||
|
def PYFUNCTYPE(restype, *argtypes):
|
||||||
|
class CFunctionType(_CFuncPtr):
|
||||||
|
_argtypes_ = argtypes
|
||||||
|
_restype_ = restype
|
||||||
|
_flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
|
||||||
|
return CFunctionType
|
||||||
|
|
||||||
|
_cast = PYFUNCTYPE(py_object, c_void_p, py_object, py_object)(_cast_addr)
|
||||||
|
def cast(obj, typ):
|
||||||
|
return _cast(obj, obj, typ)
|
||||||
|
|
||||||
|
_string_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr)
|
||||||
|
def string_at(ptr, size=-1):
|
||||||
|
"""string_at(addr[, size]) -> string
|
||||||
|
|
||||||
|
Return the string at addr."""
|
||||||
|
return _string_at(ptr, size)
|
||||||
|
|
||||||
|
try:
|
||||||
|
from _ctypes import _wstring_at_addr
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
_wstring_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_wstring_at_addr)
|
||||||
|
def wstring_at(ptr, size=-1):
|
||||||
|
"""wstring_at(addr[, size]) -> string
|
||||||
|
|
||||||
|
Return the string at addr."""
|
||||||
|
return _wstring_at(ptr, size)
|
||||||
|
|
||||||
|
|
||||||
|
if _os.name == "nt": # COM stuff
|
||||||
|
def DllGetClassObject(rclsid, riid, ppv):
|
||||||
|
try:
|
||||||
|
ccom = __import__("comtypes.server.inprocserver", globals(), locals(), ['*'])
|
||||||
|
except ImportError:
|
||||||
|
return -2147221231 # CLASS_E_CLASSNOTAVAILABLE
|
||||||
|
else:
|
||||||
|
return ccom.DllGetClassObject(rclsid, riid, ppv)
|
||||||
|
|
||||||
|
def DllCanUnloadNow():
|
||||||
|
try:
|
||||||
|
ccom = __import__("comtypes.server.inprocserver", globals(), locals(), ['*'])
|
||||||
|
except ImportError:
|
||||||
|
return 0 # S_OK
|
||||||
|
return ccom.DllCanUnloadNow()
|
||||||
|
|
||||||
|
from ctypes._endian import BigEndianStructure, LittleEndianStructure
|
||||||
|
from ctypes._endian import BigEndianUnion, LittleEndianUnion
|
||||||
|
|
||||||
|
# Fill in specifically-sized types
|
||||||
|
c_int8 = c_byte
|
||||||
|
c_uint8 = c_ubyte
|
||||||
|
for kind in [c_short, c_int, c_long, c_longlong]:
|
||||||
|
if sizeof(kind) == 2: c_int16 = kind
|
||||||
|
elif sizeof(kind) == 4: c_int32 = kind
|
||||||
|
elif sizeof(kind) == 8: c_int64 = kind
|
||||||
|
for kind in [c_ushort, c_uint, c_ulong, c_ulonglong]:
|
||||||
|
if sizeof(kind) == 2: c_uint16 = kind
|
||||||
|
elif sizeof(kind) == 4: c_uint32 = kind
|
||||||
|
elif sizeof(kind) == 8: c_uint64 = kind
|
||||||
|
del(kind)
|
||||||
|
|
||||||
|
if SIZEOF_TIME_T == 8:
|
||||||
|
c_time_t = c_int64
|
||||||
|
elif SIZEOF_TIME_T == 4:
|
||||||
|
c_time_t = c_int32
|
||||||
|
else:
|
||||||
|
raise SystemError(f"Unexpected sizeof(time_t): {SIZEOF_TIME_T=}")
|
||||||
|
|
||||||
|
_reset_cache()
|
||||||
327
Lib/ctypes/_aix.py
vendored
Normal file
327
Lib/ctypes/_aix.py
vendored
Normal file
@@ -0,0 +1,327 @@
|
|||||||
|
"""
|
||||||
|
Lib/ctypes.util.find_library() support for AIX
|
||||||
|
Similar approach as done for Darwin support by using separate files
|
||||||
|
but unlike Darwin - no extension such as ctypes.macholib.*
|
||||||
|
|
||||||
|
dlopen() is an interface to AIX initAndLoad() - primary documentation at:
|
||||||
|
https://www.ibm.com/support/knowledgecenter/en/ssw_aix_61/com.ibm.aix.basetrf1/dlopen.htm
|
||||||
|
https://www.ibm.com/support/knowledgecenter/en/ssw_aix_61/com.ibm.aix.basetrf1/load.htm
|
||||||
|
|
||||||
|
AIX supports two styles for dlopen(): svr4 (System V Release 4) which is common on posix
|
||||||
|
platforms, but also a BSD style - aka SVR3.
|
||||||
|
|
||||||
|
From AIX 5.3 Difference Addendum (December 2004)
|
||||||
|
2.9 SVR4 linking affinity
|
||||||
|
Nowadays, there are two major object file formats used by the operating systems:
|
||||||
|
XCOFF: The COFF enhanced by IBM and others. The original COFF (Common
|
||||||
|
Object File Format) was the base of SVR3 and BSD 4.2 systems.
|
||||||
|
ELF: Executable and Linking Format that was developed by AT&T and is a
|
||||||
|
base for SVR4 UNIX.
|
||||||
|
|
||||||
|
While the shared library content is identical on AIX - one is located as a filepath name
|
||||||
|
(svr4 style) and the other is located as a member of an archive (and the archive
|
||||||
|
is located as a filepath name).
|
||||||
|
|
||||||
|
The key difference arises when supporting multiple abi formats (i.e., 32 and 64 bit).
|
||||||
|
For svr4 either only one ABI is supported, or there are two directories, or there
|
||||||
|
are different file names. The most common solution for multiple ABI is multiple
|
||||||
|
directories.
|
||||||
|
|
||||||
|
For the XCOFF (aka AIX) style - one directory (one archive file) is sufficient
|
||||||
|
as multiple shared libraries can be in the archive - even sharing the same name.
|
||||||
|
In documentation the archive is also referred to as the "base" and the shared
|
||||||
|
library object is referred to as the "member".
|
||||||
|
|
||||||
|
For dlopen() on AIX (read initAndLoad()) the calls are similar.
|
||||||
|
Default activity occurs when no path information is provided. When path
|
||||||
|
information is provided dlopen() does not search any other directories.
|
||||||
|
|
||||||
|
For SVR4 - the shared library name is the name of the file expected: libFOO.so
|
||||||
|
For AIX - the shared library is expressed as base(member). The search is for the
|
||||||
|
base (e.g., libFOO.a) and once the base is found the shared library - identified by
|
||||||
|
member (e.g., libFOO.so, or shr.o) is located and loaded.
|
||||||
|
|
||||||
|
The mode bit RTLD_MEMBER tells initAndLoad() that it needs to use the AIX (SVR3)
|
||||||
|
naming style.
|
||||||
|
"""
|
||||||
|
__author__ = "Michael Felt <aixtools@felt.demon.nl>"
|
||||||
|
|
||||||
|
import re
|
||||||
|
from os import environ, path
|
||||||
|
from sys import executable
|
||||||
|
from ctypes import c_void_p, sizeof
|
||||||
|
from subprocess import Popen, PIPE, DEVNULL
|
||||||
|
|
||||||
|
# Executable bit size - 32 or 64
|
||||||
|
# Used to filter the search in an archive by size, e.g., -X64
|
||||||
|
AIX_ABI = sizeof(c_void_p) * 8
|
||||||
|
|
||||||
|
|
||||||
|
from sys import maxsize
|
||||||
|
def _last_version(libnames, sep):
|
||||||
|
def _num_version(libname):
|
||||||
|
# "libxyz.so.MAJOR.MINOR" => [MAJOR, MINOR]
|
||||||
|
parts = libname.split(sep)
|
||||||
|
nums = []
|
||||||
|
try:
|
||||||
|
while parts:
|
||||||
|
nums.insert(0, int(parts.pop()))
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
return nums or [maxsize]
|
||||||
|
return max(reversed(libnames), key=_num_version)
|
||||||
|
|
||||||
|
def get_ld_header(p):
|
||||||
|
# "nested-function, but placed at module level
|
||||||
|
ld_header = None
|
||||||
|
for line in p.stdout:
|
||||||
|
if line.startswith(('/', './', '../')):
|
||||||
|
ld_header = line
|
||||||
|
elif "INDEX" in line:
|
||||||
|
return ld_header.rstrip('\n')
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_ld_header_info(p):
|
||||||
|
# "nested-function, but placed at module level
|
||||||
|
# as an ld_header was found, return known paths, archives and members
|
||||||
|
# these lines start with a digit
|
||||||
|
info = []
|
||||||
|
for line in p.stdout:
|
||||||
|
if re.match("[0-9]", line):
|
||||||
|
info.append(line)
|
||||||
|
else:
|
||||||
|
# blank line (separator), consume line and end for loop
|
||||||
|
break
|
||||||
|
return info
|
||||||
|
|
||||||
|
def get_ld_headers(file):
|
||||||
|
"""
|
||||||
|
Parse the header of the loader section of executable and archives
|
||||||
|
This function calls /usr/bin/dump -H as a subprocess
|
||||||
|
and returns a list of (ld_header, ld_header_info) tuples.
|
||||||
|
"""
|
||||||
|
# get_ld_headers parsing:
|
||||||
|
# 1. Find a line that starts with /, ./, or ../ - set as ld_header
|
||||||
|
# 2. If "INDEX" in occurs in a following line - return ld_header
|
||||||
|
# 3. get info (lines starting with [0-9])
|
||||||
|
ldr_headers = []
|
||||||
|
p = Popen(["/usr/bin/dump", f"-X{AIX_ABI}", "-H", file],
|
||||||
|
universal_newlines=True, stdout=PIPE, stderr=DEVNULL)
|
||||||
|
# be sure to read to the end-of-file - getting all entries
|
||||||
|
while ld_header := get_ld_header(p):
|
||||||
|
ldr_headers.append((ld_header, get_ld_header_info(p)))
|
||||||
|
p.stdout.close()
|
||||||
|
p.wait()
|
||||||
|
return ldr_headers
|
||||||
|
|
||||||
|
def get_shared(ld_headers):
|
||||||
|
"""
|
||||||
|
extract the shareable objects from ld_headers
|
||||||
|
character "[" is used to strip off the path information.
|
||||||
|
Note: the "[" and "]" characters that are part of dump -H output
|
||||||
|
are not removed here.
|
||||||
|
"""
|
||||||
|
shared = []
|
||||||
|
for (line, _) in ld_headers:
|
||||||
|
# potential member lines contain "["
|
||||||
|
# otherwise, no processing needed
|
||||||
|
if "[" in line:
|
||||||
|
# Strip off trailing colon (:)
|
||||||
|
shared.append(line[line.index("["):-1])
|
||||||
|
return shared
|
||||||
|
|
||||||
|
def get_one_match(expr, lines):
|
||||||
|
"""
|
||||||
|
Must be only one match, otherwise result is None.
|
||||||
|
When there is a match, strip leading "[" and trailing "]"
|
||||||
|
"""
|
||||||
|
# member names in the ld_headers output are between square brackets
|
||||||
|
expr = rf'\[({expr})\]'
|
||||||
|
matches = list(filter(None, (re.search(expr, line) for line in lines)))
|
||||||
|
if len(matches) == 1:
|
||||||
|
return matches[0].group(1)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# additional processing to deal with AIX legacy names for 64-bit members
|
||||||
|
def get_legacy(members):
|
||||||
|
"""
|
||||||
|
This routine provides historical aka legacy naming schemes started
|
||||||
|
in AIX4 shared library support for library members names.
|
||||||
|
e.g., in /usr/lib/libc.a the member name shr.o for 32-bit binary and
|
||||||
|
shr_64.o for 64-bit binary.
|
||||||
|
"""
|
||||||
|
if AIX_ABI == 64:
|
||||||
|
# AIX 64-bit member is one of shr64.o, shr_64.o, or shr4_64.o
|
||||||
|
expr = r'shr4?_?64\.o'
|
||||||
|
member = get_one_match(expr, members)
|
||||||
|
if member:
|
||||||
|
return member
|
||||||
|
else:
|
||||||
|
# 32-bit legacy names - both shr.o and shr4.o exist.
|
||||||
|
# shr.o is the preferred name so we look for shr.o first
|
||||||
|
# i.e., shr4.o is returned only when shr.o does not exist
|
||||||
|
for name in ['shr.o', 'shr4.o']:
|
||||||
|
member = get_one_match(re.escape(name), members)
|
||||||
|
if member:
|
||||||
|
return member
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_version(name, members):
|
||||||
|
"""
|
||||||
|
Sort list of members and return highest numbered version - if it exists.
|
||||||
|
This function is called when an unversioned libFOO.a(libFOO.so) has
|
||||||
|
not been found.
|
||||||
|
|
||||||
|
Versioning for the member name is expected to follow
|
||||||
|
GNU LIBTOOL conventions: the highest version (x, then X.y, then X.Y.z)
|
||||||
|
* find [libFoo.so.X]
|
||||||
|
* find [libFoo.so.X.Y]
|
||||||
|
* find [libFoo.so.X.Y.Z]
|
||||||
|
|
||||||
|
Before the GNU convention became the standard scheme regardless of
|
||||||
|
binary size AIX packagers used GNU convention "as-is" for 32-bit
|
||||||
|
archive members but used an "distinguishing" name for 64-bit members.
|
||||||
|
This scheme inserted either 64 or _64 between libFOO and .so
|
||||||
|
- generally libFOO_64.so, but occasionally libFOO64.so
|
||||||
|
"""
|
||||||
|
# the expression ending for versions must start as
|
||||||
|
# '.so.[0-9]', i.e., *.so.[at least one digit]
|
||||||
|
# while multiple, more specific expressions could be specified
|
||||||
|
# to search for .so.X, .so.X.Y and .so.X.Y.Z
|
||||||
|
# after the first required 'dot' digit
|
||||||
|
# any combination of additional 'dot' digits pairs are accepted
|
||||||
|
# anything more than libFOO.so.digits.digits.digits
|
||||||
|
# should be seen as a member name outside normal expectations
|
||||||
|
exprs = [rf'lib{name}\.so\.[0-9]+[0-9.]*',
|
||||||
|
rf'lib{name}_?64\.so\.[0-9]+[0-9.]*']
|
||||||
|
for expr in exprs:
|
||||||
|
versions = []
|
||||||
|
for line in members:
|
||||||
|
m = re.search(expr, line)
|
||||||
|
if m:
|
||||||
|
versions.append(m.group(0))
|
||||||
|
if versions:
|
||||||
|
return _last_version(versions, '.')
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_member(name, members):
|
||||||
|
"""
|
||||||
|
Return an archive member matching the request in name.
|
||||||
|
Name is the library name without any prefix like lib, suffix like .so,
|
||||||
|
or version number.
|
||||||
|
Given a list of members find and return the most appropriate result
|
||||||
|
Priority is given to generic libXXX.so, then a versioned libXXX.so.a.b.c
|
||||||
|
and finally, legacy AIX naming scheme.
|
||||||
|
"""
|
||||||
|
# look first for a generic match - prepend lib and append .so
|
||||||
|
expr = rf'lib{name}\.so'
|
||||||
|
member = get_one_match(expr, members)
|
||||||
|
if member:
|
||||||
|
return member
|
||||||
|
elif AIX_ABI == 64:
|
||||||
|
expr = rf'lib{name}64\.so'
|
||||||
|
member = get_one_match(expr, members)
|
||||||
|
if member:
|
||||||
|
return member
|
||||||
|
# since an exact match with .so as suffix was not found
|
||||||
|
# look for a versioned name
|
||||||
|
# If a versioned name is not found, look for AIX legacy member name
|
||||||
|
member = get_version(name, members)
|
||||||
|
if member:
|
||||||
|
return member
|
||||||
|
else:
|
||||||
|
return get_legacy(members)
|
||||||
|
|
||||||
|
def get_libpaths():
|
||||||
|
"""
|
||||||
|
On AIX, the buildtime searchpath is stored in the executable.
|
||||||
|
as "loader header information".
|
||||||
|
The command /usr/bin/dump -H extracts this info.
|
||||||
|
Prefix searched libraries with LD_LIBRARY_PATH (preferred),
|
||||||
|
or LIBPATH if defined. These paths are appended to the paths
|
||||||
|
to libraries the python executable is linked with.
|
||||||
|
This mimics AIX dlopen() behavior.
|
||||||
|
"""
|
||||||
|
libpaths = environ.get("LD_LIBRARY_PATH")
|
||||||
|
if libpaths is None:
|
||||||
|
libpaths = environ.get("LIBPATH")
|
||||||
|
if libpaths is None:
|
||||||
|
libpaths = []
|
||||||
|
else:
|
||||||
|
libpaths = libpaths.split(":")
|
||||||
|
objects = get_ld_headers(executable)
|
||||||
|
for (_, lines) in objects:
|
||||||
|
for line in lines:
|
||||||
|
# the second (optional) argument is PATH if it includes a /
|
||||||
|
path = line.split()[1]
|
||||||
|
if "/" in path:
|
||||||
|
libpaths.extend(path.split(":"))
|
||||||
|
return libpaths
|
||||||
|
|
||||||
|
def find_shared(paths, name):
|
||||||
|
"""
|
||||||
|
paths is a list of directories to search for an archive.
|
||||||
|
name is the abbreviated name given to find_library().
|
||||||
|
Process: search "paths" for archive, and if an archive is found
|
||||||
|
return the result of get_member().
|
||||||
|
If an archive is not found then return None
|
||||||
|
"""
|
||||||
|
for dir in paths:
|
||||||
|
# /lib is a symbolic link to /usr/lib, skip it
|
||||||
|
if dir == "/lib":
|
||||||
|
continue
|
||||||
|
# "lib" is prefixed to emulate compiler name resolution,
|
||||||
|
# e.g., -lc to libc
|
||||||
|
base = f'lib{name}.a'
|
||||||
|
archive = path.join(dir, base)
|
||||||
|
if path.exists(archive):
|
||||||
|
members = get_shared(get_ld_headers(archive))
|
||||||
|
member = get_member(re.escape(name), members)
|
||||||
|
if member is not None:
|
||||||
|
return (base, member)
|
||||||
|
else:
|
||||||
|
return (None, None)
|
||||||
|
return (None, None)
|
||||||
|
|
||||||
|
def find_library(name):
|
||||||
|
"""AIX implementation of ctypes.util.find_library()
|
||||||
|
Find an archive member that will dlopen(). If not available,
|
||||||
|
also search for a file (or link) with a .so suffix.
|
||||||
|
|
||||||
|
AIX supports two types of schemes that can be used with dlopen().
|
||||||
|
The so-called SystemV Release4 (svr4) format is commonly suffixed
|
||||||
|
with .so while the (default) AIX scheme has the library (archive)
|
||||||
|
ending with the suffix .a
|
||||||
|
As an archive has multiple members (e.g., 32-bit and 64-bit) in one file
|
||||||
|
the argument passed to dlopen must include both the library and
|
||||||
|
the member names in a single string.
|
||||||
|
|
||||||
|
find_library() looks first for an archive (.a) with a suitable member.
|
||||||
|
If no archive+member pair is found, look for a .so file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
libpaths = get_libpaths()
|
||||||
|
(base, member) = find_shared(libpaths, name)
|
||||||
|
if base is not None:
|
||||||
|
return f"{base}({member})"
|
||||||
|
|
||||||
|
# To get here, a member in an archive has not been found
|
||||||
|
# In other words, either:
|
||||||
|
# a) a .a file was not found
|
||||||
|
# b) a .a file did not have a suitable member
|
||||||
|
# So, look for a .so file
|
||||||
|
# Check libpaths for .so file
|
||||||
|
# Note, the installation must prepare a link from a .so
|
||||||
|
# to a versioned file
|
||||||
|
# This is common practice by GNU libtool on other platforms
|
||||||
|
soname = f"lib{name}.so"
|
||||||
|
for dir in libpaths:
|
||||||
|
# /lib is a symbolic link to /usr/lib, skip it
|
||||||
|
if dir == "/lib":
|
||||||
|
continue
|
||||||
|
shlib = path.join(dir, soname)
|
||||||
|
if path.exists(shlib):
|
||||||
|
return soname
|
||||||
|
# if we are here, we have not found anything plausible
|
||||||
|
return None
|
||||||
78
Lib/ctypes/_endian.py
vendored
Normal file
78
Lib/ctypes/_endian.py
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import sys
|
||||||
|
from ctypes import *
|
||||||
|
|
||||||
|
_array_type = type(Array)
|
||||||
|
|
||||||
|
def _other_endian(typ):
|
||||||
|
"""Return the type with the 'other' byte order. Simple types like
|
||||||
|
c_int and so on already have __ctype_be__ and __ctype_le__
|
||||||
|
attributes which contain the types, for more complicated types
|
||||||
|
arrays and structures are supported.
|
||||||
|
"""
|
||||||
|
# check _OTHER_ENDIAN attribute (present if typ is primitive type)
|
||||||
|
if hasattr(typ, _OTHER_ENDIAN):
|
||||||
|
return getattr(typ, _OTHER_ENDIAN)
|
||||||
|
# if typ is array
|
||||||
|
if isinstance(typ, _array_type):
|
||||||
|
return _other_endian(typ._type_) * typ._length_
|
||||||
|
# if typ is structure
|
||||||
|
if issubclass(typ, Structure):
|
||||||
|
return typ
|
||||||
|
raise TypeError("This type does not support other endian: %s" % typ)
|
||||||
|
|
||||||
|
class _swapped_meta:
|
||||||
|
def __setattr__(self, attrname, value):
|
||||||
|
if attrname == "_fields_":
|
||||||
|
fields = []
|
||||||
|
for desc in value:
|
||||||
|
name = desc[0]
|
||||||
|
typ = desc[1]
|
||||||
|
rest = desc[2:]
|
||||||
|
fields.append((name, _other_endian(typ)) + rest)
|
||||||
|
value = fields
|
||||||
|
super().__setattr__(attrname, value)
|
||||||
|
class _swapped_struct_meta(_swapped_meta, type(Structure)): pass
|
||||||
|
class _swapped_union_meta(_swapped_meta, type(Union)): pass
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
# Note: The Structure metaclass checks for the *presence* (not the
|
||||||
|
# value!) of a _swapped_bytes_ attribute to determine the bit order in
|
||||||
|
# structures containing bit fields.
|
||||||
|
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
_OTHER_ENDIAN = "__ctype_be__"
|
||||||
|
|
||||||
|
LittleEndianStructure = Structure
|
||||||
|
|
||||||
|
class BigEndianStructure(Structure, metaclass=_swapped_struct_meta):
|
||||||
|
"""Structure with big endian byte order"""
|
||||||
|
__slots__ = ()
|
||||||
|
_swappedbytes_ = None
|
||||||
|
|
||||||
|
LittleEndianUnion = Union
|
||||||
|
|
||||||
|
class BigEndianUnion(Union, metaclass=_swapped_union_meta):
|
||||||
|
"""Union with big endian byte order"""
|
||||||
|
__slots__ = ()
|
||||||
|
_swappedbytes_ = None
|
||||||
|
|
||||||
|
elif sys.byteorder == "big":
|
||||||
|
_OTHER_ENDIAN = "__ctype_le__"
|
||||||
|
|
||||||
|
BigEndianStructure = Structure
|
||||||
|
|
||||||
|
class LittleEndianStructure(Structure, metaclass=_swapped_struct_meta):
|
||||||
|
"""Structure with little endian byte order"""
|
||||||
|
__slots__ = ()
|
||||||
|
_swappedbytes_ = None
|
||||||
|
|
||||||
|
BigEndianUnion = Union
|
||||||
|
|
||||||
|
class LittleEndianUnion(Union, metaclass=_swapped_union_meta):
|
||||||
|
"""Union with little endian byte order"""
|
||||||
|
__slots__ = ()
|
||||||
|
_swappedbytes_ = None
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise RuntimeError("Invalid byteorder")
|
||||||
7
Lib/ctypes/macholib/README.ctypes
vendored
Normal file
7
Lib/ctypes/macholib/README.ctypes
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Files in this directory come from Bob Ippolito's py2app.
|
||||||
|
|
||||||
|
License: Any components of the py2app suite may be distributed under
|
||||||
|
the MIT or PSF open source licenses.
|
||||||
|
|
||||||
|
This is version 1.0, SVN revision 789, from 2006/01/25.
|
||||||
|
The main repository is http://svn.red-bean.com/bob/macholib/trunk/macholib/
|
||||||
9
Lib/ctypes/macholib/__init__.py
vendored
Normal file
9
Lib/ctypes/macholib/__init__.py
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
"""
|
||||||
|
Enough Mach-O to make your head spin.
|
||||||
|
|
||||||
|
See the relevant header files in /usr/include/mach-o
|
||||||
|
|
||||||
|
And also Apple's documentation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__version__ = '1.0'
|
||||||
165
Lib/ctypes/macholib/dyld.py
vendored
Normal file
165
Lib/ctypes/macholib/dyld.py
vendored
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
"""
|
||||||
|
dyld emulation
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from ctypes.macholib.framework import framework_info
|
||||||
|
from ctypes.macholib.dylib import dylib_info
|
||||||
|
from itertools import *
|
||||||
|
try:
|
||||||
|
from _ctypes import _dyld_shared_cache_contains_path
|
||||||
|
except ImportError:
|
||||||
|
def _dyld_shared_cache_contains_path(*args):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'dyld_find', 'framework_find',
|
||||||
|
'framework_info', 'dylib_info',
|
||||||
|
]
|
||||||
|
|
||||||
|
# These are the defaults as per man dyld(1)
|
||||||
|
#
|
||||||
|
DEFAULT_FRAMEWORK_FALLBACK = [
|
||||||
|
os.path.expanduser("~/Library/Frameworks"),
|
||||||
|
"/Library/Frameworks",
|
||||||
|
"/Network/Library/Frameworks",
|
||||||
|
"/System/Library/Frameworks",
|
||||||
|
]
|
||||||
|
|
||||||
|
DEFAULT_LIBRARY_FALLBACK = [
|
||||||
|
os.path.expanduser("~/lib"),
|
||||||
|
"/usr/local/lib",
|
||||||
|
"/lib",
|
||||||
|
"/usr/lib",
|
||||||
|
]
|
||||||
|
|
||||||
|
def dyld_env(env, var):
|
||||||
|
if env is None:
|
||||||
|
env = os.environ
|
||||||
|
rval = env.get(var)
|
||||||
|
if rval is None:
|
||||||
|
return []
|
||||||
|
return rval.split(':')
|
||||||
|
|
||||||
|
def dyld_image_suffix(env=None):
|
||||||
|
if env is None:
|
||||||
|
env = os.environ
|
||||||
|
return env.get('DYLD_IMAGE_SUFFIX')
|
||||||
|
|
||||||
|
def dyld_framework_path(env=None):
|
||||||
|
return dyld_env(env, 'DYLD_FRAMEWORK_PATH')
|
||||||
|
|
||||||
|
def dyld_library_path(env=None):
|
||||||
|
return dyld_env(env, 'DYLD_LIBRARY_PATH')
|
||||||
|
|
||||||
|
def dyld_fallback_framework_path(env=None):
|
||||||
|
return dyld_env(env, 'DYLD_FALLBACK_FRAMEWORK_PATH')
|
||||||
|
|
||||||
|
def dyld_fallback_library_path(env=None):
|
||||||
|
return dyld_env(env, 'DYLD_FALLBACK_LIBRARY_PATH')
|
||||||
|
|
||||||
|
def dyld_image_suffix_search(iterator, env=None):
|
||||||
|
"""For a potential path iterator, add DYLD_IMAGE_SUFFIX semantics"""
|
||||||
|
suffix = dyld_image_suffix(env)
|
||||||
|
if suffix is None:
|
||||||
|
return iterator
|
||||||
|
def _inject(iterator=iterator, suffix=suffix):
|
||||||
|
for path in iterator:
|
||||||
|
if path.endswith('.dylib'):
|
||||||
|
yield path[:-len('.dylib')] + suffix + '.dylib'
|
||||||
|
else:
|
||||||
|
yield path + suffix
|
||||||
|
yield path
|
||||||
|
return _inject()
|
||||||
|
|
||||||
|
def dyld_override_search(name, env=None):
|
||||||
|
# If DYLD_FRAMEWORK_PATH is set and this dylib_name is a
|
||||||
|
# framework name, use the first file that exists in the framework
|
||||||
|
# path if any. If there is none go on to search the DYLD_LIBRARY_PATH
|
||||||
|
# if any.
|
||||||
|
|
||||||
|
framework = framework_info(name)
|
||||||
|
|
||||||
|
if framework is not None:
|
||||||
|
for path in dyld_framework_path(env):
|
||||||
|
yield os.path.join(path, framework['name'])
|
||||||
|
|
||||||
|
# If DYLD_LIBRARY_PATH is set then use the first file that exists
|
||||||
|
# in the path. If none use the original name.
|
||||||
|
for path in dyld_library_path(env):
|
||||||
|
yield os.path.join(path, os.path.basename(name))
|
||||||
|
|
||||||
|
def dyld_executable_path_search(name, executable_path=None):
|
||||||
|
# If we haven't done any searching and found a library and the
|
||||||
|
# dylib_name starts with "@executable_path/" then construct the
|
||||||
|
# library name.
|
||||||
|
if name.startswith('@executable_path/') and executable_path is not None:
|
||||||
|
yield os.path.join(executable_path, name[len('@executable_path/'):])
|
||||||
|
|
||||||
|
def dyld_default_search(name, env=None):
|
||||||
|
yield name
|
||||||
|
|
||||||
|
framework = framework_info(name)
|
||||||
|
|
||||||
|
if framework is not None:
|
||||||
|
fallback_framework_path = dyld_fallback_framework_path(env)
|
||||||
|
for path in fallback_framework_path:
|
||||||
|
yield os.path.join(path, framework['name'])
|
||||||
|
|
||||||
|
fallback_library_path = dyld_fallback_library_path(env)
|
||||||
|
for path in fallback_library_path:
|
||||||
|
yield os.path.join(path, os.path.basename(name))
|
||||||
|
|
||||||
|
if framework is not None and not fallback_framework_path:
|
||||||
|
for path in DEFAULT_FRAMEWORK_FALLBACK:
|
||||||
|
yield os.path.join(path, framework['name'])
|
||||||
|
|
||||||
|
if not fallback_library_path:
|
||||||
|
for path in DEFAULT_LIBRARY_FALLBACK:
|
||||||
|
yield os.path.join(path, os.path.basename(name))
|
||||||
|
|
||||||
|
def dyld_find(name, executable_path=None, env=None):
|
||||||
|
"""
|
||||||
|
Find a library or framework using dyld semantics
|
||||||
|
"""
|
||||||
|
for path in dyld_image_suffix_search(chain(
|
||||||
|
dyld_override_search(name, env),
|
||||||
|
dyld_executable_path_search(name, executable_path),
|
||||||
|
dyld_default_search(name, env),
|
||||||
|
), env):
|
||||||
|
|
||||||
|
if os.path.isfile(path):
|
||||||
|
return path
|
||||||
|
try:
|
||||||
|
if _dyld_shared_cache_contains_path(path):
|
||||||
|
return path
|
||||||
|
except NotImplementedError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
raise ValueError("dylib %s could not be found" % (name,))
|
||||||
|
|
||||||
|
def framework_find(fn, executable_path=None, env=None):
|
||||||
|
"""
|
||||||
|
Find a framework using dyld semantics in a very loose manner.
|
||||||
|
|
||||||
|
Will take input such as:
|
||||||
|
Python
|
||||||
|
Python.framework
|
||||||
|
Python.framework/Versions/Current
|
||||||
|
"""
|
||||||
|
error = None
|
||||||
|
try:
|
||||||
|
return dyld_find(fn, executable_path=executable_path, env=env)
|
||||||
|
except ValueError as e:
|
||||||
|
error = e
|
||||||
|
fmwk_index = fn.rfind('.framework')
|
||||||
|
if fmwk_index == -1:
|
||||||
|
fmwk_index = len(fn)
|
||||||
|
fn += '.framework'
|
||||||
|
fn = os.path.join(fn, os.path.basename(fn[:fmwk_index]))
|
||||||
|
try:
|
||||||
|
return dyld_find(fn, executable_path=executable_path, env=env)
|
||||||
|
except ValueError:
|
||||||
|
raise error
|
||||||
|
finally:
|
||||||
|
error = None
|
||||||
42
Lib/ctypes/macholib/dylib.py
vendored
Normal file
42
Lib/ctypes/macholib/dylib.py
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
"""
|
||||||
|
Generic dylib path manipulation
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
__all__ = ['dylib_info']
|
||||||
|
|
||||||
|
DYLIB_RE = re.compile(r"""(?x)
|
||||||
|
(?P<location>^.*)(?:^|/)
|
||||||
|
(?P<name>
|
||||||
|
(?P<shortname>\w+?)
|
||||||
|
(?:\.(?P<version>[^._]+))?
|
||||||
|
(?:_(?P<suffix>[^._]+))?
|
||||||
|
\.dylib$
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
def dylib_info(filename):
|
||||||
|
"""
|
||||||
|
A dylib name can take one of the following four forms:
|
||||||
|
Location/Name.SomeVersion_Suffix.dylib
|
||||||
|
Location/Name.SomeVersion.dylib
|
||||||
|
Location/Name_Suffix.dylib
|
||||||
|
Location/Name.dylib
|
||||||
|
|
||||||
|
returns None if not found or a mapping equivalent to:
|
||||||
|
dict(
|
||||||
|
location='Location',
|
||||||
|
name='Name.SomeVersion_Suffix.dylib',
|
||||||
|
shortname='Name',
|
||||||
|
version='SomeVersion',
|
||||||
|
suffix='Suffix',
|
||||||
|
)
|
||||||
|
|
||||||
|
Note that SomeVersion and Suffix are optional and may be None
|
||||||
|
if not present.
|
||||||
|
"""
|
||||||
|
is_dylib = DYLIB_RE.match(filename)
|
||||||
|
if not is_dylib:
|
||||||
|
return None
|
||||||
|
return is_dylib.groupdict()
|
||||||
2
Lib/ctypes/macholib/fetch_macholib
vendored
Executable file
2
Lib/ctypes/macholib/fetch_macholib
vendored
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
svn export --force http://svn.red-bean.com/bob/macholib/trunk/macholib/ .
|
||||||
1
Lib/ctypes/macholib/fetch_macholib.bat
vendored
Normal file
1
Lib/ctypes/macholib/fetch_macholib.bat
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
svn export --force http://svn.red-bean.com/bob/macholib/trunk/macholib/ .
|
||||||
42
Lib/ctypes/macholib/framework.py
vendored
Normal file
42
Lib/ctypes/macholib/framework.py
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
"""
|
||||||
|
Generic framework path manipulation
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
__all__ = ['framework_info']
|
||||||
|
|
||||||
|
STRICT_FRAMEWORK_RE = re.compile(r"""(?x)
|
||||||
|
(?P<location>^.*)(?:^|/)
|
||||||
|
(?P<name>
|
||||||
|
(?P<shortname>\w+).framework/
|
||||||
|
(?:Versions/(?P<version>[^/]+)/)?
|
||||||
|
(?P=shortname)
|
||||||
|
(?:_(?P<suffix>[^_]+))?
|
||||||
|
)$
|
||||||
|
""")
|
||||||
|
|
||||||
|
def framework_info(filename):
|
||||||
|
"""
|
||||||
|
A framework name can take one of the following four forms:
|
||||||
|
Location/Name.framework/Versions/SomeVersion/Name_Suffix
|
||||||
|
Location/Name.framework/Versions/SomeVersion/Name
|
||||||
|
Location/Name.framework/Name_Suffix
|
||||||
|
Location/Name.framework/Name
|
||||||
|
|
||||||
|
returns None if not found, or a mapping equivalent to:
|
||||||
|
dict(
|
||||||
|
location='Location',
|
||||||
|
name='Name.framework/Versions/SomeVersion/Name_Suffix',
|
||||||
|
shortname='Name',
|
||||||
|
version='SomeVersion',
|
||||||
|
suffix='Suffix',
|
||||||
|
)
|
||||||
|
|
||||||
|
Note that SomeVersion and Suffix are optional and may be None
|
||||||
|
if not present
|
||||||
|
"""
|
||||||
|
is_framework = STRICT_FRAMEWORK_RE.match(filename)
|
||||||
|
if not is_framework:
|
||||||
|
return None
|
||||||
|
return is_framework.groupdict()
|
||||||
16
Lib/ctypes/test/__init__.py
vendored
Normal file
16
Lib/ctypes/test/__init__.py
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
from test import support
|
||||||
|
from test.support import import_helper
|
||||||
|
|
||||||
|
|
||||||
|
# skip tests if _ctypes was not built
|
||||||
|
ctypes = import_helper.import_module('ctypes')
|
||||||
|
ctypes_symbols = dir(ctypes)
|
||||||
|
|
||||||
|
def need_symbol(name):
|
||||||
|
return unittest.skipUnless(name in ctypes_symbols,
|
||||||
|
'{!r} is required'.format(name))
|
||||||
|
|
||||||
|
def load_tests(*args):
|
||||||
|
return support.load_package_tests(os.path.dirname(__file__), *args)
|
||||||
4
Lib/ctypes/test/__main__.py
vendored
Normal file
4
Lib/ctypes/test/__main__.py
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
from ctypes.test import load_tests
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
unittest.main()
|
||||||
73
Lib/ctypes/test/test_anon.py
vendored
Normal file
73
Lib/ctypes/test/test_anon.py
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import unittest
|
||||||
|
import test.support
|
||||||
|
from ctypes import *
|
||||||
|
|
||||||
|
class AnonTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_anon(self):
|
||||||
|
class ANON(Union):
|
||||||
|
_fields_ = [("a", c_int),
|
||||||
|
("b", c_int)]
|
||||||
|
|
||||||
|
class Y(Structure):
|
||||||
|
_fields_ = [("x", c_int),
|
||||||
|
("_", ANON),
|
||||||
|
("y", c_int)]
|
||||||
|
_anonymous_ = ["_"]
|
||||||
|
|
||||||
|
self.assertEqual(Y.a.offset, sizeof(c_int))
|
||||||
|
self.assertEqual(Y.b.offset, sizeof(c_int))
|
||||||
|
|
||||||
|
self.assertEqual(ANON.a.offset, 0)
|
||||||
|
self.assertEqual(ANON.b.offset, 0)
|
||||||
|
|
||||||
|
def test_anon_nonseq(self):
|
||||||
|
# TypeError: _anonymous_ must be a sequence
|
||||||
|
self.assertRaises(TypeError,
|
||||||
|
lambda: type(Structure)("Name",
|
||||||
|
(Structure,),
|
||||||
|
{"_fields_": [], "_anonymous_": 42}))
|
||||||
|
|
||||||
|
def test_anon_nonmember(self):
|
||||||
|
# AttributeError: type object 'Name' has no attribute 'x'
|
||||||
|
self.assertRaises(AttributeError,
|
||||||
|
lambda: type(Structure)("Name",
|
||||||
|
(Structure,),
|
||||||
|
{"_fields_": [],
|
||||||
|
"_anonymous_": ["x"]}))
|
||||||
|
|
||||||
|
@test.support.cpython_only
|
||||||
|
def test_issue31490(self):
|
||||||
|
# There shouldn't be an assertion failure in case the class has an
|
||||||
|
# attribute whose name is specified in _anonymous_ but not in _fields_.
|
||||||
|
|
||||||
|
# AttributeError: 'x' is specified in _anonymous_ but not in _fields_
|
||||||
|
with self.assertRaises(AttributeError):
|
||||||
|
class Name(Structure):
|
||||||
|
_fields_ = []
|
||||||
|
_anonymous_ = ["x"]
|
||||||
|
x = 42
|
||||||
|
|
||||||
|
def test_nested(self):
|
||||||
|
class ANON_S(Structure):
|
||||||
|
_fields_ = [("a", c_int)]
|
||||||
|
|
||||||
|
class ANON_U(Union):
|
||||||
|
_fields_ = [("_", ANON_S),
|
||||||
|
("b", c_int)]
|
||||||
|
_anonymous_ = ["_"]
|
||||||
|
|
||||||
|
class Y(Structure):
|
||||||
|
_fields_ = [("x", c_int),
|
||||||
|
("_", ANON_U),
|
||||||
|
("y", c_int)]
|
||||||
|
_anonymous_ = ["_"]
|
||||||
|
|
||||||
|
self.assertEqual(Y.x.offset, 0)
|
||||||
|
self.assertEqual(Y.a.offset, sizeof(c_int))
|
||||||
|
self.assertEqual(Y.b.offset, sizeof(c_int))
|
||||||
|
self.assertEqual(Y._.offset, sizeof(c_int))
|
||||||
|
self.assertEqual(Y.y.offset, sizeof(c_int) * 2)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
64
Lib/ctypes/test/test_array_in_pointer.py
vendored
Normal file
64
Lib/ctypes/test/test_array_in_pointer.py
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import unittest
|
||||||
|
from ctypes import *
|
||||||
|
from binascii import hexlify
|
||||||
|
import re
|
||||||
|
|
||||||
|
def dump(obj):
|
||||||
|
# helper function to dump memory contents in hex, with a hyphen
|
||||||
|
# between the bytes.
|
||||||
|
h = hexlify(memoryview(obj)).decode()
|
||||||
|
return re.sub(r"(..)", r"\1-", h)[:-1]
|
||||||
|
|
||||||
|
|
||||||
|
class Value(Structure):
|
||||||
|
_fields_ = [("val", c_byte)]
|
||||||
|
|
||||||
|
class Container(Structure):
|
||||||
|
_fields_ = [("pvalues", POINTER(Value))]
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
def test(self):
|
||||||
|
# create an array of 4 values
|
||||||
|
val_array = (Value * 4)()
|
||||||
|
|
||||||
|
# create a container, which holds a pointer to the pvalues array.
|
||||||
|
c = Container()
|
||||||
|
c.pvalues = val_array
|
||||||
|
|
||||||
|
# memory contains 4 NUL bytes now, that's correct
|
||||||
|
self.assertEqual("00-00-00-00", dump(val_array))
|
||||||
|
|
||||||
|
# set the values of the array through the pointer:
|
||||||
|
for i in range(4):
|
||||||
|
c.pvalues[i].val = i + 1
|
||||||
|
|
||||||
|
values = [c.pvalues[i].val for i in range(4)]
|
||||||
|
|
||||||
|
# These are the expected results: here s the bug!
|
||||||
|
self.assertEqual(
|
||||||
|
(values, dump(val_array)),
|
||||||
|
([1, 2, 3, 4], "01-02-03-04")
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_2(self):
|
||||||
|
|
||||||
|
val_array = (Value * 4)()
|
||||||
|
|
||||||
|
# memory contains 4 NUL bytes now, that's correct
|
||||||
|
self.assertEqual("00-00-00-00", dump(val_array))
|
||||||
|
|
||||||
|
ptr = cast(val_array, POINTER(Value))
|
||||||
|
# set the values of the array through the pointer:
|
||||||
|
for i in range(4):
|
||||||
|
ptr[i].val = i + 1
|
||||||
|
|
||||||
|
values = [ptr[i].val for i in range(4)]
|
||||||
|
|
||||||
|
# These are the expected results: here s the bug!
|
||||||
|
self.assertEqual(
|
||||||
|
(values, dump(val_array)),
|
||||||
|
([1, 2, 3, 4], "01-02-03-04")
|
||||||
|
)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
238
Lib/ctypes/test/test_arrays.py
vendored
Normal file
238
Lib/ctypes/test/test_arrays.py
vendored
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
import unittest
|
||||||
|
from test.support import bigmemtest, _2G
|
||||||
|
import sys
|
||||||
|
from ctypes import *
|
||||||
|
|
||||||
|
from ctypes.test import need_symbol
|
||||||
|
|
||||||
|
formats = "bBhHiIlLqQfd"
|
||||||
|
|
||||||
|
formats = c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, \
|
||||||
|
c_long, c_ulonglong, c_float, c_double, c_longdouble
|
||||||
|
|
||||||
|
class ArrayTestCase(unittest.TestCase):
|
||||||
|
def test_simple(self):
|
||||||
|
# create classes holding simple numeric types, and check
|
||||||
|
# various properties.
|
||||||
|
|
||||||
|
init = list(range(15, 25))
|
||||||
|
|
||||||
|
for fmt in formats:
|
||||||
|
alen = len(init)
|
||||||
|
int_array = ARRAY(fmt, alen)
|
||||||
|
|
||||||
|
ia = int_array(*init)
|
||||||
|
# length of instance ok?
|
||||||
|
self.assertEqual(len(ia), alen)
|
||||||
|
|
||||||
|
# slot values ok?
|
||||||
|
values = [ia[i] for i in range(alen)]
|
||||||
|
self.assertEqual(values, init)
|
||||||
|
|
||||||
|
# out-of-bounds accesses should be caught
|
||||||
|
with self.assertRaises(IndexError): ia[alen]
|
||||||
|
with self.assertRaises(IndexError): ia[-alen-1]
|
||||||
|
|
||||||
|
# change the items
|
||||||
|
from operator import setitem
|
||||||
|
new_values = list(range(42, 42+alen))
|
||||||
|
[setitem(ia, n, new_values[n]) for n in range(alen)]
|
||||||
|
values = [ia[i] for i in range(alen)]
|
||||||
|
self.assertEqual(values, new_values)
|
||||||
|
|
||||||
|
# are the items initialized to 0?
|
||||||
|
ia = int_array()
|
||||||
|
values = [ia[i] for i in range(alen)]
|
||||||
|
self.assertEqual(values, [0] * alen)
|
||||||
|
|
||||||
|
# Too many initializers should be caught
|
||||||
|
self.assertRaises(IndexError, int_array, *range(alen*2))
|
||||||
|
|
||||||
|
CharArray = ARRAY(c_char, 3)
|
||||||
|
|
||||||
|
ca = CharArray(b"a", b"b", b"c")
|
||||||
|
|
||||||
|
# Should this work? It doesn't:
|
||||||
|
# CharArray("abc")
|
||||||
|
self.assertRaises(TypeError, CharArray, "abc")
|
||||||
|
|
||||||
|
self.assertEqual(ca[0], b"a")
|
||||||
|
self.assertEqual(ca[1], b"b")
|
||||||
|
self.assertEqual(ca[2], b"c")
|
||||||
|
self.assertEqual(ca[-3], b"a")
|
||||||
|
self.assertEqual(ca[-2], b"b")
|
||||||
|
self.assertEqual(ca[-1], b"c")
|
||||||
|
|
||||||
|
self.assertEqual(len(ca), 3)
|
||||||
|
|
||||||
|
# cannot delete items
|
||||||
|
from operator import delitem
|
||||||
|
self.assertRaises(TypeError, delitem, ca, 0)
|
||||||
|
|
||||||
|
def test_step_overflow(self):
|
||||||
|
a = (c_int * 5)()
|
||||||
|
a[3::sys.maxsize] = (1,)
|
||||||
|
self.assertListEqual(a[3::sys.maxsize], [1])
|
||||||
|
a = (c_char * 5)()
|
||||||
|
a[3::sys.maxsize] = b"A"
|
||||||
|
self.assertEqual(a[3::sys.maxsize], b"A")
|
||||||
|
a = (c_wchar * 5)()
|
||||||
|
a[3::sys.maxsize] = u"X"
|
||||||
|
self.assertEqual(a[3::sys.maxsize], u"X")
|
||||||
|
|
||||||
|
def test_numeric_arrays(self):
|
||||||
|
|
||||||
|
alen = 5
|
||||||
|
|
||||||
|
numarray = ARRAY(c_int, alen)
|
||||||
|
|
||||||
|
na = numarray()
|
||||||
|
values = [na[i] for i in range(alen)]
|
||||||
|
self.assertEqual(values, [0] * alen)
|
||||||
|
|
||||||
|
na = numarray(*[c_int()] * alen)
|
||||||
|
values = [na[i] for i in range(alen)]
|
||||||
|
self.assertEqual(values, [0]*alen)
|
||||||
|
|
||||||
|
na = numarray(1, 2, 3, 4, 5)
|
||||||
|
values = [i for i in na]
|
||||||
|
self.assertEqual(values, [1, 2, 3, 4, 5])
|
||||||
|
|
||||||
|
na = numarray(*map(c_int, (1, 2, 3, 4, 5)))
|
||||||
|
values = [i for i in na]
|
||||||
|
self.assertEqual(values, [1, 2, 3, 4, 5])
|
||||||
|
|
||||||
|
def test_classcache(self):
|
||||||
|
self.assertIsNot(ARRAY(c_int, 3), ARRAY(c_int, 4))
|
||||||
|
self.assertIs(ARRAY(c_int, 3), ARRAY(c_int, 3))
|
||||||
|
|
||||||
|
def test_from_address(self):
|
||||||
|
# Failed with 0.9.8, reported by JUrner
|
||||||
|
p = create_string_buffer(b"foo")
|
||||||
|
sz = (c_char * 3).from_address(addressof(p))
|
||||||
|
self.assertEqual(sz[:], b"foo")
|
||||||
|
self.assertEqual(sz[::], b"foo")
|
||||||
|
self.assertEqual(sz[::-1], b"oof")
|
||||||
|
self.assertEqual(sz[::3], b"f")
|
||||||
|
self.assertEqual(sz[1:4:2], b"o")
|
||||||
|
self.assertEqual(sz.value, b"foo")
|
||||||
|
|
||||||
|
@need_symbol('create_unicode_buffer')
|
||||||
|
def test_from_addressW(self):
|
||||||
|
p = create_unicode_buffer("foo")
|
||||||
|
sz = (c_wchar * 3).from_address(addressof(p))
|
||||||
|
self.assertEqual(sz[:], "foo")
|
||||||
|
self.assertEqual(sz[::], "foo")
|
||||||
|
self.assertEqual(sz[::-1], "oof")
|
||||||
|
self.assertEqual(sz[::3], "f")
|
||||||
|
self.assertEqual(sz[1:4:2], "o")
|
||||||
|
self.assertEqual(sz.value, "foo")
|
||||||
|
|
||||||
|
def test_cache(self):
|
||||||
|
# Array types are cached internally in the _ctypes extension,
|
||||||
|
# in a WeakValueDictionary. Make sure the array type is
|
||||||
|
# removed from the cache when the itemtype goes away. This
|
||||||
|
# test will not fail, but will show a leak in the testsuite.
|
||||||
|
|
||||||
|
# Create a new type:
|
||||||
|
class my_int(c_int):
|
||||||
|
pass
|
||||||
|
# Create a new array type based on it:
|
||||||
|
t1 = my_int * 1
|
||||||
|
t2 = my_int * 1
|
||||||
|
self.assertIs(t1, t2)
|
||||||
|
|
||||||
|
def test_subclass(self):
|
||||||
|
class T(Array):
|
||||||
|
_type_ = c_int
|
||||||
|
_length_ = 13
|
||||||
|
class U(T):
|
||||||
|
pass
|
||||||
|
class V(U):
|
||||||
|
pass
|
||||||
|
class W(V):
|
||||||
|
pass
|
||||||
|
class X(T):
|
||||||
|
_type_ = c_short
|
||||||
|
class Y(T):
|
||||||
|
_length_ = 187
|
||||||
|
|
||||||
|
for c in [T, U, V, W]:
|
||||||
|
self.assertEqual(c._type_, c_int)
|
||||||
|
self.assertEqual(c._length_, 13)
|
||||||
|
self.assertEqual(c()._type_, c_int)
|
||||||
|
self.assertEqual(c()._length_, 13)
|
||||||
|
|
||||||
|
self.assertEqual(X._type_, c_short)
|
||||||
|
self.assertEqual(X._length_, 13)
|
||||||
|
self.assertEqual(X()._type_, c_short)
|
||||||
|
self.assertEqual(X()._length_, 13)
|
||||||
|
|
||||||
|
self.assertEqual(Y._type_, c_int)
|
||||||
|
self.assertEqual(Y._length_, 187)
|
||||||
|
self.assertEqual(Y()._type_, c_int)
|
||||||
|
self.assertEqual(Y()._length_, 187)
|
||||||
|
|
||||||
|
def test_bad_subclass(self):
|
||||||
|
with self.assertRaises(AttributeError):
|
||||||
|
class T(Array):
|
||||||
|
pass
|
||||||
|
with self.assertRaises(AttributeError):
|
||||||
|
class T(Array):
|
||||||
|
_type_ = c_int
|
||||||
|
with self.assertRaises(AttributeError):
|
||||||
|
class T(Array):
|
||||||
|
_length_ = 13
|
||||||
|
|
||||||
|
def test_bad_length(self):
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
class T(Array):
|
||||||
|
_type_ = c_int
|
||||||
|
_length_ = - sys.maxsize * 2
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
class T(Array):
|
||||||
|
_type_ = c_int
|
||||||
|
_length_ = -1
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
class T(Array):
|
||||||
|
_type_ = c_int
|
||||||
|
_length_ = 1.87
|
||||||
|
with self.assertRaises(OverflowError):
|
||||||
|
class T(Array):
|
||||||
|
_type_ = c_int
|
||||||
|
_length_ = sys.maxsize * 2
|
||||||
|
|
||||||
|
def test_zero_length(self):
|
||||||
|
# _length_ can be zero.
|
||||||
|
class T(Array):
|
||||||
|
_type_ = c_int
|
||||||
|
_length_ = 0
|
||||||
|
|
||||||
|
def test_empty_element_struct(self):
|
||||||
|
class EmptyStruct(Structure):
|
||||||
|
_fields_ = []
|
||||||
|
|
||||||
|
obj = (EmptyStruct * 2)() # bpo37188: Floating point exception
|
||||||
|
self.assertEqual(sizeof(obj), 0)
|
||||||
|
|
||||||
|
def test_empty_element_array(self):
|
||||||
|
class EmptyArray(Array):
|
||||||
|
_type_ = c_int
|
||||||
|
_length_ = 0
|
||||||
|
|
||||||
|
obj = (EmptyArray * 2)() # bpo37188: Floating point exception
|
||||||
|
self.assertEqual(sizeof(obj), 0)
|
||||||
|
|
||||||
|
def test_bpo36504_signed_int_overflow(self):
|
||||||
|
# The overflow check in PyCArrayType_new() could cause signed integer
|
||||||
|
# overflow.
|
||||||
|
with self.assertRaises(OverflowError):
|
||||||
|
c_char * sys.maxsize * 2
|
||||||
|
|
||||||
|
@unittest.skipUnless(sys.maxsize > 2**32, 'requires 64bit platform')
|
||||||
|
@bigmemtest(size=_2G, memuse=1, dry_run=False)
|
||||||
|
def test_large_array(self, size):
|
||||||
|
c_char * size
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
231
Lib/ctypes/test/test_as_parameter.py
vendored
Normal file
231
Lib/ctypes/test/test_as_parameter.py
vendored
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
import unittest
|
||||||
|
from ctypes import *
|
||||||
|
from ctypes.test import need_symbol
|
||||||
|
import _ctypes_test
|
||||||
|
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
|
||||||
|
try:
|
||||||
|
CALLBACK_FUNCTYPE = WINFUNCTYPE
|
||||||
|
except NameError:
|
||||||
|
# fake to enable this test on Linux
|
||||||
|
CALLBACK_FUNCTYPE = CFUNCTYPE
|
||||||
|
|
||||||
|
class POINT(Structure):
|
||||||
|
_fields_ = [("x", c_int), ("y", c_int)]
|
||||||
|
|
||||||
|
class BasicWrapTestCase(unittest.TestCase):
|
||||||
|
def wrap(self, param):
|
||||||
|
return param
|
||||||
|
|
||||||
|
@need_symbol('c_wchar')
|
||||||
|
def test_wchar_parm(self):
|
||||||
|
f = dll._testfunc_i_bhilfd
|
||||||
|
f.argtypes = [c_byte, c_wchar, c_int, c_long, c_float, c_double]
|
||||||
|
result = f(self.wrap(1), self.wrap("x"), self.wrap(3), self.wrap(4), self.wrap(5.0), self.wrap(6.0))
|
||||||
|
self.assertEqual(result, 139)
|
||||||
|
self.assertIs(type(result), int)
|
||||||
|
|
||||||
|
def test_pointers(self):
|
||||||
|
f = dll._testfunc_p_p
|
||||||
|
f.restype = POINTER(c_int)
|
||||||
|
f.argtypes = [POINTER(c_int)]
|
||||||
|
|
||||||
|
# This only works if the value c_int(42) passed to the
|
||||||
|
# function is still alive while the pointer (the result) is
|
||||||
|
# used.
|
||||||
|
|
||||||
|
v = c_int(42)
|
||||||
|
|
||||||
|
self.assertEqual(pointer(v).contents.value, 42)
|
||||||
|
result = f(self.wrap(pointer(v)))
|
||||||
|
self.assertEqual(type(result), POINTER(c_int))
|
||||||
|
self.assertEqual(result.contents.value, 42)
|
||||||
|
|
||||||
|
# This on works...
|
||||||
|
result = f(self.wrap(pointer(v)))
|
||||||
|
self.assertEqual(result.contents.value, v.value)
|
||||||
|
|
||||||
|
p = pointer(c_int(99))
|
||||||
|
result = f(self.wrap(p))
|
||||||
|
self.assertEqual(result.contents.value, 99)
|
||||||
|
|
||||||
|
def test_shorts(self):
|
||||||
|
f = dll._testfunc_callback_i_if
|
||||||
|
|
||||||
|
args = []
|
||||||
|
expected = [262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048,
|
||||||
|
1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1]
|
||||||
|
|
||||||
|
def callback(v):
|
||||||
|
args.append(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
CallBack = CFUNCTYPE(c_int, c_int)
|
||||||
|
|
||||||
|
cb = CallBack(callback)
|
||||||
|
f(self.wrap(2**18), self.wrap(cb))
|
||||||
|
self.assertEqual(args, expected)
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
def test_callbacks(self):
|
||||||
|
f = dll._testfunc_callback_i_if
|
||||||
|
f.restype = c_int
|
||||||
|
f.argtypes = None
|
||||||
|
|
||||||
|
MyCallback = CFUNCTYPE(c_int, c_int)
|
||||||
|
|
||||||
|
def callback(value):
|
||||||
|
#print "called back with", value
|
||||||
|
return value
|
||||||
|
|
||||||
|
cb = MyCallback(callback)
|
||||||
|
|
||||||
|
result = f(self.wrap(-10), self.wrap(cb))
|
||||||
|
self.assertEqual(result, -18)
|
||||||
|
|
||||||
|
# test with prototype
|
||||||
|
f.argtypes = [c_int, MyCallback]
|
||||||
|
cb = MyCallback(callback)
|
||||||
|
|
||||||
|
result = f(self.wrap(-10), self.wrap(cb))
|
||||||
|
self.assertEqual(result, -18)
|
||||||
|
|
||||||
|
result = f(self.wrap(-10), self.wrap(cb))
|
||||||
|
self.assertEqual(result, -18)
|
||||||
|
|
||||||
|
AnotherCallback = CALLBACK_FUNCTYPE(c_int, c_int, c_int, c_int, c_int)
|
||||||
|
|
||||||
|
# check that the prototype works: we call f with wrong
|
||||||
|
# argument types
|
||||||
|
cb = AnotherCallback(callback)
|
||||||
|
self.assertRaises(ArgumentError, f, self.wrap(-10), self.wrap(cb))
|
||||||
|
|
||||||
|
def test_callbacks_2(self):
|
||||||
|
# Can also use simple datatypes as argument type specifiers
|
||||||
|
# for the callback function.
|
||||||
|
# In this case the call receives an instance of that type
|
||||||
|
f = dll._testfunc_callback_i_if
|
||||||
|
f.restype = c_int
|
||||||
|
|
||||||
|
MyCallback = CFUNCTYPE(c_int, c_int)
|
||||||
|
|
||||||
|
f.argtypes = [c_int, MyCallback]
|
||||||
|
|
||||||
|
def callback(value):
|
||||||
|
#print "called back with", value
|
||||||
|
self.assertEqual(type(value), int)
|
||||||
|
return value
|
||||||
|
|
||||||
|
cb = MyCallback(callback)
|
||||||
|
result = f(self.wrap(-10), self.wrap(cb))
|
||||||
|
self.assertEqual(result, -18)
|
||||||
|
|
||||||
|
@need_symbol('c_longlong')
|
||||||
|
def test_longlong_callbacks(self):
|
||||||
|
|
||||||
|
f = dll._testfunc_callback_q_qf
|
||||||
|
f.restype = c_longlong
|
||||||
|
|
||||||
|
MyCallback = CFUNCTYPE(c_longlong, c_longlong)
|
||||||
|
|
||||||
|
f.argtypes = [c_longlong, MyCallback]
|
||||||
|
|
||||||
|
def callback(value):
|
||||||
|
self.assertIsInstance(value, int)
|
||||||
|
return value & 0x7FFFFFFF
|
||||||
|
|
||||||
|
cb = MyCallback(callback)
|
||||||
|
|
||||||
|
self.assertEqual(13577625587, int(f(self.wrap(1000000000000), self.wrap(cb))))
|
||||||
|
|
||||||
|
def test_byval(self):
|
||||||
|
# without prototype
|
||||||
|
ptin = POINT(1, 2)
|
||||||
|
ptout = POINT()
|
||||||
|
# EXPORT int _testfunc_byval(point in, point *pout)
|
||||||
|
result = dll._testfunc_byval(ptin, byref(ptout))
|
||||||
|
got = result, ptout.x, ptout.y
|
||||||
|
expected = 3, 1, 2
|
||||||
|
self.assertEqual(got, expected)
|
||||||
|
|
||||||
|
# with prototype
|
||||||
|
ptin = POINT(101, 102)
|
||||||
|
ptout = POINT()
|
||||||
|
dll._testfunc_byval.argtypes = (POINT, POINTER(POINT))
|
||||||
|
dll._testfunc_byval.restype = c_int
|
||||||
|
result = dll._testfunc_byval(self.wrap(ptin), byref(ptout))
|
||||||
|
got = result, ptout.x, ptout.y
|
||||||
|
expected = 203, 101, 102
|
||||||
|
self.assertEqual(got, expected)
|
||||||
|
|
||||||
|
def test_struct_return_2H(self):
|
||||||
|
class S2H(Structure):
|
||||||
|
_fields_ = [("x", c_short),
|
||||||
|
("y", c_short)]
|
||||||
|
dll.ret_2h_func.restype = S2H
|
||||||
|
dll.ret_2h_func.argtypes = [S2H]
|
||||||
|
inp = S2H(99, 88)
|
||||||
|
s2h = dll.ret_2h_func(self.wrap(inp))
|
||||||
|
self.assertEqual((s2h.x, s2h.y), (99*2, 88*3))
|
||||||
|
|
||||||
|
# Test also that the original struct was unmodified (i.e. was passed by
|
||||||
|
# value)
|
||||||
|
self.assertEqual((inp.x, inp.y), (99, 88))
|
||||||
|
|
||||||
|
def test_struct_return_8H(self):
|
||||||
|
class S8I(Structure):
|
||||||
|
_fields_ = [("a", c_int),
|
||||||
|
("b", c_int),
|
||||||
|
("c", c_int),
|
||||||
|
("d", c_int),
|
||||||
|
("e", c_int),
|
||||||
|
("f", c_int),
|
||||||
|
("g", c_int),
|
||||||
|
("h", c_int)]
|
||||||
|
dll.ret_8i_func.restype = S8I
|
||||||
|
dll.ret_8i_func.argtypes = [S8I]
|
||||||
|
inp = S8I(9, 8, 7, 6, 5, 4, 3, 2)
|
||||||
|
s8i = dll.ret_8i_func(self.wrap(inp))
|
||||||
|
self.assertEqual((s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h),
|
||||||
|
(9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9))
|
||||||
|
|
||||||
|
def test_recursive_as_param(self):
|
||||||
|
from ctypes import c_int
|
||||||
|
|
||||||
|
class A(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
a = A()
|
||||||
|
a._as_parameter_ = a
|
||||||
|
with self.assertRaises(RecursionError):
|
||||||
|
c_int.from_param(a)
|
||||||
|
|
||||||
|
|
||||||
|
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
class AsParamWrapper(object):
|
||||||
|
def __init__(self, param):
|
||||||
|
self._as_parameter_ = param
|
||||||
|
|
||||||
|
class AsParamWrapperTestCase(BasicWrapTestCase):
|
||||||
|
wrap = AsParamWrapper
|
||||||
|
|
||||||
|
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
class AsParamPropertyWrapper(object):
|
||||||
|
def __init__(self, param):
|
||||||
|
self._param = param
|
||||||
|
|
||||||
|
def getParameter(self):
|
||||||
|
return self._param
|
||||||
|
_as_parameter_ = property(getParameter)
|
||||||
|
|
||||||
|
class AsParamPropertyWrapperTestCase(BasicWrapTestCase):
|
||||||
|
wrap = AsParamPropertyWrapper
|
||||||
|
|
||||||
|
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
297
Lib/ctypes/test/test_bitfields.py
vendored
Normal file
297
Lib/ctypes/test/test_bitfields.py
vendored
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
from ctypes import *
|
||||||
|
from ctypes.test import need_symbol
|
||||||
|
from test import support
|
||||||
|
import unittest
|
||||||
|
import os
|
||||||
|
|
||||||
|
import _ctypes_test
|
||||||
|
|
||||||
|
class BITS(Structure):
|
||||||
|
_fields_ = [("A", c_int, 1),
|
||||||
|
("B", c_int, 2),
|
||||||
|
("C", c_int, 3),
|
||||||
|
("D", c_int, 4),
|
||||||
|
("E", c_int, 5),
|
||||||
|
("F", c_int, 6),
|
||||||
|
("G", c_int, 7),
|
||||||
|
("H", c_int, 8),
|
||||||
|
("I", c_int, 9),
|
||||||
|
|
||||||
|
("M", c_short, 1),
|
||||||
|
("N", c_short, 2),
|
||||||
|
("O", c_short, 3),
|
||||||
|
("P", c_short, 4),
|
||||||
|
("Q", c_short, 5),
|
||||||
|
("R", c_short, 6),
|
||||||
|
("S", c_short, 7)]
|
||||||
|
|
||||||
|
func = CDLL(_ctypes_test.__file__).unpack_bitfields
|
||||||
|
func.argtypes = POINTER(BITS), c_char
|
||||||
|
|
||||||
|
##for n in "ABCDEFGHIMNOPQRS":
|
||||||
|
## print n, hex(getattr(BITS, n).size), getattr(BITS, n).offset
|
||||||
|
|
||||||
|
class C_Test(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_ints(self):
|
||||||
|
for i in range(512):
|
||||||
|
for name in "ABCDEFGHI":
|
||||||
|
b = BITS()
|
||||||
|
setattr(b, name, i)
|
||||||
|
self.assertEqual(getattr(b, name), func(byref(b), name.encode('ascii')))
|
||||||
|
|
||||||
|
# bpo-46913: _ctypes/cfield.c h_get() has an undefined behavior
|
||||||
|
@support.skip_if_sanitizer(ub=True)
|
||||||
|
def test_shorts(self):
|
||||||
|
b = BITS()
|
||||||
|
name = "M"
|
||||||
|
if func(byref(b), name.encode('ascii')) == 999:
|
||||||
|
self.skipTest("Compiler does not support signed short bitfields")
|
||||||
|
for i in range(256):
|
||||||
|
for name in "MNOPQRS":
|
||||||
|
b = BITS()
|
||||||
|
setattr(b, name, i)
|
||||||
|
self.assertEqual(getattr(b, name), func(byref(b), name.encode('ascii')))
|
||||||
|
|
||||||
|
signed_int_types = (c_byte, c_short, c_int, c_long, c_longlong)
|
||||||
|
unsigned_int_types = (c_ubyte, c_ushort, c_uint, c_ulong, c_ulonglong)
|
||||||
|
int_types = unsigned_int_types + signed_int_types
|
||||||
|
|
||||||
|
class BitFieldTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_longlong(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_longlong, 1),
|
||||||
|
("b", c_longlong, 62),
|
||||||
|
("c", c_longlong, 1)]
|
||||||
|
|
||||||
|
self.assertEqual(sizeof(X), sizeof(c_longlong))
|
||||||
|
x = X()
|
||||||
|
x.a, x.b, x.c = -1, 7, -1
|
||||||
|
self.assertEqual((x.a, x.b, x.c), (-1, 7, -1))
|
||||||
|
|
||||||
|
def test_ulonglong(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_ulonglong, 1),
|
||||||
|
("b", c_ulonglong, 62),
|
||||||
|
("c", c_ulonglong, 1)]
|
||||||
|
|
||||||
|
self.assertEqual(sizeof(X), sizeof(c_longlong))
|
||||||
|
x = X()
|
||||||
|
self.assertEqual((x.a, x.b, x.c), (0, 0, 0))
|
||||||
|
x.a, x.b, x.c = 7, 7, 7
|
||||||
|
self.assertEqual((x.a, x.b, x.c), (1, 7, 1))
|
||||||
|
|
||||||
|
def test_signed(self):
|
||||||
|
for c_typ in signed_int_types:
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("dummy", c_typ),
|
||||||
|
("a", c_typ, 3),
|
||||||
|
("b", c_typ, 3),
|
||||||
|
("c", c_typ, 1)]
|
||||||
|
self.assertEqual(sizeof(X), sizeof(c_typ)*2)
|
||||||
|
|
||||||
|
x = X()
|
||||||
|
self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, 0, 0))
|
||||||
|
x.a = -1
|
||||||
|
self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, -1, 0, 0))
|
||||||
|
x.a, x.b = 0, -1
|
||||||
|
self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, -1, 0))
|
||||||
|
|
||||||
|
|
||||||
|
def test_unsigned(self):
|
||||||
|
for c_typ in unsigned_int_types:
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_typ, 3),
|
||||||
|
("b", c_typ, 3),
|
||||||
|
("c", c_typ, 1)]
|
||||||
|
self.assertEqual(sizeof(X), sizeof(c_typ))
|
||||||
|
|
||||||
|
x = X()
|
||||||
|
self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, 0, 0))
|
||||||
|
x.a = -1
|
||||||
|
self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 7, 0, 0))
|
||||||
|
x.a, x.b = 0, -1
|
||||||
|
self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, 7, 0))
|
||||||
|
|
||||||
|
|
||||||
|
def fail_fields(self, *fields):
|
||||||
|
return self.get_except(type(Structure), "X", (),
|
||||||
|
{"_fields_": fields})
|
||||||
|
|
||||||
|
def test_nonint_types(self):
|
||||||
|
# bit fields are not allowed on non-integer types.
|
||||||
|
result = self.fail_fields(("a", c_char_p, 1))
|
||||||
|
self.assertEqual(result, (TypeError, 'bit fields not allowed for type c_char_p'))
|
||||||
|
|
||||||
|
result = self.fail_fields(("a", c_void_p, 1))
|
||||||
|
self.assertEqual(result, (TypeError, 'bit fields not allowed for type c_void_p'))
|
||||||
|
|
||||||
|
if c_int != c_long:
|
||||||
|
result = self.fail_fields(("a", POINTER(c_int), 1))
|
||||||
|
self.assertEqual(result, (TypeError, 'bit fields not allowed for type LP_c_int'))
|
||||||
|
|
||||||
|
result = self.fail_fields(("a", c_char, 1))
|
||||||
|
self.assertEqual(result, (TypeError, 'bit fields not allowed for type c_char'))
|
||||||
|
|
||||||
|
class Dummy(Structure):
|
||||||
|
_fields_ = []
|
||||||
|
|
||||||
|
result = self.fail_fields(("a", Dummy, 1))
|
||||||
|
self.assertEqual(result, (TypeError, 'bit fields not allowed for type Dummy'))
|
||||||
|
|
||||||
|
@need_symbol('c_wchar')
|
||||||
|
def test_c_wchar(self):
|
||||||
|
result = self.fail_fields(("a", c_wchar, 1))
|
||||||
|
self.assertEqual(result,
|
||||||
|
(TypeError, 'bit fields not allowed for type c_wchar'))
|
||||||
|
|
||||||
|
def test_single_bitfield_size(self):
|
||||||
|
for c_typ in int_types:
|
||||||
|
result = self.fail_fields(("a", c_typ, -1))
|
||||||
|
self.assertEqual(result, (ValueError, 'number of bits invalid for bit field'))
|
||||||
|
|
||||||
|
result = self.fail_fields(("a", c_typ, 0))
|
||||||
|
self.assertEqual(result, (ValueError, 'number of bits invalid for bit field'))
|
||||||
|
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_typ, 1)]
|
||||||
|
self.assertEqual(sizeof(X), sizeof(c_typ))
|
||||||
|
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_typ, sizeof(c_typ)*8)]
|
||||||
|
self.assertEqual(sizeof(X), sizeof(c_typ))
|
||||||
|
|
||||||
|
result = self.fail_fields(("a", c_typ, sizeof(c_typ)*8 + 1))
|
||||||
|
self.assertEqual(result, (ValueError, 'number of bits invalid for bit field'))
|
||||||
|
|
||||||
|
def test_multi_bitfields_size(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_short, 1),
|
||||||
|
("b", c_short, 14),
|
||||||
|
("c", c_short, 1)]
|
||||||
|
self.assertEqual(sizeof(X), sizeof(c_short))
|
||||||
|
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_short, 1),
|
||||||
|
("a1", c_short),
|
||||||
|
("b", c_short, 14),
|
||||||
|
("c", c_short, 1)]
|
||||||
|
self.assertEqual(sizeof(X), sizeof(c_short)*3)
|
||||||
|
self.assertEqual(X.a.offset, 0)
|
||||||
|
self.assertEqual(X.a1.offset, sizeof(c_short))
|
||||||
|
self.assertEqual(X.b.offset, sizeof(c_short)*2)
|
||||||
|
self.assertEqual(X.c.offset, sizeof(c_short)*2)
|
||||||
|
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_short, 3),
|
||||||
|
("b", c_short, 14),
|
||||||
|
("c", c_short, 14)]
|
||||||
|
self.assertEqual(sizeof(X), sizeof(c_short)*3)
|
||||||
|
self.assertEqual(X.a.offset, sizeof(c_short)*0)
|
||||||
|
self.assertEqual(X.b.offset, sizeof(c_short)*1)
|
||||||
|
self.assertEqual(X.c.offset, sizeof(c_short)*2)
|
||||||
|
|
||||||
|
|
||||||
|
def get_except(self, func, *args, **kw):
|
||||||
|
try:
|
||||||
|
func(*args, **kw)
|
||||||
|
except Exception as detail:
|
||||||
|
return detail.__class__, str(detail)
|
||||||
|
|
||||||
|
def test_mixed_1(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_byte, 4),
|
||||||
|
("b", c_int, 4)]
|
||||||
|
if os.name == "nt":
|
||||||
|
self.assertEqual(sizeof(X), sizeof(c_int)*2)
|
||||||
|
else:
|
||||||
|
self.assertEqual(sizeof(X), sizeof(c_int))
|
||||||
|
|
||||||
|
def test_mixed_2(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_byte, 4),
|
||||||
|
("b", c_int, 32)]
|
||||||
|
self.assertEqual(sizeof(X), alignment(c_int)+sizeof(c_int))
|
||||||
|
|
||||||
|
def test_mixed_3(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_byte, 4),
|
||||||
|
("b", c_ubyte, 4)]
|
||||||
|
self.assertEqual(sizeof(X), sizeof(c_byte))
|
||||||
|
|
||||||
|
def test_mixed_4(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_short, 4),
|
||||||
|
("b", c_short, 4),
|
||||||
|
("c", c_int, 24),
|
||||||
|
("d", c_short, 4),
|
||||||
|
("e", c_short, 4),
|
||||||
|
("f", c_int, 24)]
|
||||||
|
# MSVC does NOT combine c_short and c_int into one field, GCC
|
||||||
|
# does (unless GCC is run with '-mms-bitfields' which
|
||||||
|
# produces code compatible with MSVC).
|
||||||
|
if os.name == "nt":
|
||||||
|
self.assertEqual(sizeof(X), sizeof(c_int) * 4)
|
||||||
|
else:
|
||||||
|
self.assertEqual(sizeof(X), sizeof(c_int) * 2)
|
||||||
|
|
||||||
|
def test_anon_bitfields(self):
|
||||||
|
# anonymous bit-fields gave a strange error message
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_byte, 4),
|
||||||
|
("b", c_ubyte, 4)]
|
||||||
|
class Y(Structure):
|
||||||
|
_anonymous_ = ["_"]
|
||||||
|
_fields_ = [("_", X)]
|
||||||
|
|
||||||
|
@need_symbol('c_uint32')
|
||||||
|
def test_uint32(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_uint32, 32)]
|
||||||
|
x = X()
|
||||||
|
x.a = 10
|
||||||
|
self.assertEqual(x.a, 10)
|
||||||
|
x.a = 0xFDCBA987
|
||||||
|
self.assertEqual(x.a, 0xFDCBA987)
|
||||||
|
|
||||||
|
@need_symbol('c_uint64')
|
||||||
|
def test_uint64(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_uint64, 64)]
|
||||||
|
x = X()
|
||||||
|
x.a = 10
|
||||||
|
self.assertEqual(x.a, 10)
|
||||||
|
x.a = 0xFEDCBA9876543211
|
||||||
|
self.assertEqual(x.a, 0xFEDCBA9876543211)
|
||||||
|
|
||||||
|
@need_symbol('c_uint32')
|
||||||
|
def test_uint32_swap_little_endian(self):
|
||||||
|
# Issue #23319
|
||||||
|
class Little(LittleEndianStructure):
|
||||||
|
_fields_ = [("a", c_uint32, 24),
|
||||||
|
("b", c_uint32, 4),
|
||||||
|
("c", c_uint32, 4)]
|
||||||
|
b = bytearray(4)
|
||||||
|
x = Little.from_buffer(b)
|
||||||
|
x.a = 0xabcdef
|
||||||
|
x.b = 1
|
||||||
|
x.c = 2
|
||||||
|
self.assertEqual(b, b'\xef\xcd\xab\x21')
|
||||||
|
|
||||||
|
@need_symbol('c_uint32')
|
||||||
|
def test_uint32_swap_big_endian(self):
|
||||||
|
# Issue #23319
|
||||||
|
class Big(BigEndianStructure):
|
||||||
|
_fields_ = [("a", c_uint32, 24),
|
||||||
|
("b", c_uint32, 4),
|
||||||
|
("c", c_uint32, 4)]
|
||||||
|
b = bytearray(4)
|
||||||
|
x = Big.from_buffer(b)
|
||||||
|
x.a = 0xabcdef
|
||||||
|
x.b = 1
|
||||||
|
x.c = 2
|
||||||
|
self.assertEqual(b, b'\xab\xcd\xef\x12')
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
73
Lib/ctypes/test/test_buffers.py
vendored
Normal file
73
Lib/ctypes/test/test_buffers.py
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
from ctypes import *
|
||||||
|
from ctypes.test import need_symbol
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
class StringBufferTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_buffer(self):
|
||||||
|
b = create_string_buffer(32)
|
||||||
|
self.assertEqual(len(b), 32)
|
||||||
|
self.assertEqual(sizeof(b), 32 * sizeof(c_char))
|
||||||
|
self.assertIs(type(b[0]), bytes)
|
||||||
|
|
||||||
|
b = create_string_buffer(b"abc")
|
||||||
|
self.assertEqual(len(b), 4) # trailing nul char
|
||||||
|
self.assertEqual(sizeof(b), 4 * sizeof(c_char))
|
||||||
|
self.assertIs(type(b[0]), bytes)
|
||||||
|
self.assertEqual(b[0], b"a")
|
||||||
|
self.assertEqual(b[:], b"abc\0")
|
||||||
|
self.assertEqual(b[::], b"abc\0")
|
||||||
|
self.assertEqual(b[::-1], b"\0cba")
|
||||||
|
self.assertEqual(b[::2], b"ac")
|
||||||
|
self.assertEqual(b[::5], b"a")
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, create_string_buffer, "abc")
|
||||||
|
|
||||||
|
def test_buffer_interface(self):
|
||||||
|
self.assertEqual(len(bytearray(create_string_buffer(0))), 0)
|
||||||
|
self.assertEqual(len(bytearray(create_string_buffer(1))), 1)
|
||||||
|
|
||||||
|
@need_symbol('c_wchar')
|
||||||
|
def test_unicode_buffer(self):
|
||||||
|
b = create_unicode_buffer(32)
|
||||||
|
self.assertEqual(len(b), 32)
|
||||||
|
self.assertEqual(sizeof(b), 32 * sizeof(c_wchar))
|
||||||
|
self.assertIs(type(b[0]), str)
|
||||||
|
|
||||||
|
b = create_unicode_buffer("abc")
|
||||||
|
self.assertEqual(len(b), 4) # trailing nul char
|
||||||
|
self.assertEqual(sizeof(b), 4 * sizeof(c_wchar))
|
||||||
|
self.assertIs(type(b[0]), str)
|
||||||
|
self.assertEqual(b[0], "a")
|
||||||
|
self.assertEqual(b[:], "abc\0")
|
||||||
|
self.assertEqual(b[::], "abc\0")
|
||||||
|
self.assertEqual(b[::-1], "\0cba")
|
||||||
|
self.assertEqual(b[::2], "ac")
|
||||||
|
self.assertEqual(b[::5], "a")
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, create_unicode_buffer, b"abc")
|
||||||
|
|
||||||
|
@need_symbol('c_wchar')
|
||||||
|
def test_unicode_conversion(self):
|
||||||
|
b = create_unicode_buffer("abc")
|
||||||
|
self.assertEqual(len(b), 4) # trailing nul char
|
||||||
|
self.assertEqual(sizeof(b), 4 * sizeof(c_wchar))
|
||||||
|
self.assertIs(type(b[0]), str)
|
||||||
|
self.assertEqual(b[0], "a")
|
||||||
|
self.assertEqual(b[:], "abc\0")
|
||||||
|
self.assertEqual(b[::], "abc\0")
|
||||||
|
self.assertEqual(b[::-1], "\0cba")
|
||||||
|
self.assertEqual(b[::2], "ac")
|
||||||
|
self.assertEqual(b[::5], "a")
|
||||||
|
|
||||||
|
@need_symbol('c_wchar')
|
||||||
|
def test_create_unicode_buffer_non_bmp(self):
|
||||||
|
expected = 5 if sizeof(c_wchar) == 2 else 3
|
||||||
|
for s in '\U00010000\U00100000', '\U00010000\U0010ffff':
|
||||||
|
b = create_unicode_buffer(s)
|
||||||
|
self.assertEqual(len(b), expected)
|
||||||
|
self.assertEqual(b[-1], '\0')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
66
Lib/ctypes/test/test_bytes.py
vendored
Normal file
66
Lib/ctypes/test/test_bytes.py
vendored
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
"""Test where byte objects are accepted"""
|
||||||
|
import unittest
|
||||||
|
import sys
|
||||||
|
from ctypes import *
|
||||||
|
|
||||||
|
class BytesTest(unittest.TestCase):
|
||||||
|
def test_c_char(self):
|
||||||
|
x = c_char(b"x")
|
||||||
|
self.assertRaises(TypeError, c_char, "x")
|
||||||
|
x.value = b"y"
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
x.value = "y"
|
||||||
|
c_char.from_param(b"x")
|
||||||
|
self.assertRaises(TypeError, c_char.from_param, "x")
|
||||||
|
self.assertIn('xbd', repr(c_char.from_param(b"\xbd")))
|
||||||
|
(c_char * 3)(b"a", b"b", b"c")
|
||||||
|
self.assertRaises(TypeError, c_char * 3, "a", "b", "c")
|
||||||
|
|
||||||
|
def test_c_wchar(self):
|
||||||
|
x = c_wchar("x")
|
||||||
|
self.assertRaises(TypeError, c_wchar, b"x")
|
||||||
|
x.value = "y"
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
x.value = b"y"
|
||||||
|
c_wchar.from_param("x")
|
||||||
|
self.assertRaises(TypeError, c_wchar.from_param, b"x")
|
||||||
|
(c_wchar * 3)("a", "b", "c")
|
||||||
|
self.assertRaises(TypeError, c_wchar * 3, b"a", b"b", b"c")
|
||||||
|
|
||||||
|
def test_c_char_p(self):
|
||||||
|
c_char_p(b"foo bar")
|
||||||
|
self.assertRaises(TypeError, c_char_p, "foo bar")
|
||||||
|
|
||||||
|
def test_c_wchar_p(self):
|
||||||
|
c_wchar_p("foo bar")
|
||||||
|
self.assertRaises(TypeError, c_wchar_p, b"foo bar")
|
||||||
|
|
||||||
|
def test_struct(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_char * 3)]
|
||||||
|
|
||||||
|
x = X(b"abc")
|
||||||
|
self.assertRaises(TypeError, X, "abc")
|
||||||
|
self.assertEqual(x.a, b"abc")
|
||||||
|
self.assertEqual(type(x.a), bytes)
|
||||||
|
|
||||||
|
def test_struct_W(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_wchar * 3)]
|
||||||
|
|
||||||
|
x = X("abc")
|
||||||
|
self.assertRaises(TypeError, X, b"abc")
|
||||||
|
self.assertEqual(x.a, "abc")
|
||||||
|
self.assertEqual(type(x.a), str)
|
||||||
|
|
||||||
|
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
|
||||||
|
def test_BSTR(self):
|
||||||
|
from _ctypes import _SimpleCData
|
||||||
|
class BSTR(_SimpleCData):
|
||||||
|
_type_ = "X"
|
||||||
|
|
||||||
|
BSTR("abc")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
364
Lib/ctypes/test/test_byteswap.py
vendored
Normal file
364
Lib/ctypes/test/test_byteswap.py
vendored
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
import sys, unittest, struct, math, ctypes
|
||||||
|
from binascii import hexlify
|
||||||
|
|
||||||
|
from ctypes import *
|
||||||
|
|
||||||
|
def bin(s):
|
||||||
|
return hexlify(memoryview(s)).decode().upper()
|
||||||
|
|
||||||
|
# Each *simple* type that supports different byte orders has an
|
||||||
|
# __ctype_be__ attribute that specifies the same type in BIG ENDIAN
|
||||||
|
# byte order, and a __ctype_le__ attribute that is the same type in
|
||||||
|
# LITTLE ENDIAN byte order.
|
||||||
|
#
|
||||||
|
# For Structures and Unions, these types are created on demand.
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
@unittest.skip('test disabled')
|
||||||
|
def test_X(self):
|
||||||
|
print(sys.byteorder, file=sys.stderr)
|
||||||
|
for i in range(32):
|
||||||
|
bits = BITS()
|
||||||
|
setattr(bits, "i%s" % i, 1)
|
||||||
|
dump(bits)
|
||||||
|
|
||||||
|
def test_slots(self):
|
||||||
|
class BigPoint(BigEndianStructure):
|
||||||
|
__slots__ = ()
|
||||||
|
_fields_ = [("x", c_int), ("y", c_int)]
|
||||||
|
|
||||||
|
class LowPoint(LittleEndianStructure):
|
||||||
|
__slots__ = ()
|
||||||
|
_fields_ = [("x", c_int), ("y", c_int)]
|
||||||
|
|
||||||
|
big = BigPoint()
|
||||||
|
little = LowPoint()
|
||||||
|
big.x = 4
|
||||||
|
big.y = 2
|
||||||
|
little.x = 2
|
||||||
|
little.y = 4
|
||||||
|
with self.assertRaises(AttributeError):
|
||||||
|
big.z = 42
|
||||||
|
with self.assertRaises(AttributeError):
|
||||||
|
little.z = 24
|
||||||
|
|
||||||
|
def test_endian_short(self):
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
self.assertIs(c_short.__ctype_le__, c_short)
|
||||||
|
self.assertIs(c_short.__ctype_be__.__ctype_le__, c_short)
|
||||||
|
else:
|
||||||
|
self.assertIs(c_short.__ctype_be__, c_short)
|
||||||
|
self.assertIs(c_short.__ctype_le__.__ctype_be__, c_short)
|
||||||
|
s = c_short.__ctype_be__(0x1234)
|
||||||
|
self.assertEqual(bin(struct.pack(">h", 0x1234)), "1234")
|
||||||
|
self.assertEqual(bin(s), "1234")
|
||||||
|
self.assertEqual(s.value, 0x1234)
|
||||||
|
|
||||||
|
s = c_short.__ctype_le__(0x1234)
|
||||||
|
self.assertEqual(bin(struct.pack("<h", 0x1234)), "3412")
|
||||||
|
self.assertEqual(bin(s), "3412")
|
||||||
|
self.assertEqual(s.value, 0x1234)
|
||||||
|
|
||||||
|
s = c_ushort.__ctype_be__(0x1234)
|
||||||
|
self.assertEqual(bin(struct.pack(">h", 0x1234)), "1234")
|
||||||
|
self.assertEqual(bin(s), "1234")
|
||||||
|
self.assertEqual(s.value, 0x1234)
|
||||||
|
|
||||||
|
s = c_ushort.__ctype_le__(0x1234)
|
||||||
|
self.assertEqual(bin(struct.pack("<h", 0x1234)), "3412")
|
||||||
|
self.assertEqual(bin(s), "3412")
|
||||||
|
self.assertEqual(s.value, 0x1234)
|
||||||
|
|
||||||
|
def test_endian_int(self):
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
self.assertIs(c_int.__ctype_le__, c_int)
|
||||||
|
self.assertIs(c_int.__ctype_be__.__ctype_le__, c_int)
|
||||||
|
else:
|
||||||
|
self.assertIs(c_int.__ctype_be__, c_int)
|
||||||
|
self.assertIs(c_int.__ctype_le__.__ctype_be__, c_int)
|
||||||
|
|
||||||
|
s = c_int.__ctype_be__(0x12345678)
|
||||||
|
self.assertEqual(bin(struct.pack(">i", 0x12345678)), "12345678")
|
||||||
|
self.assertEqual(bin(s), "12345678")
|
||||||
|
self.assertEqual(s.value, 0x12345678)
|
||||||
|
|
||||||
|
s = c_int.__ctype_le__(0x12345678)
|
||||||
|
self.assertEqual(bin(struct.pack("<i", 0x12345678)), "78563412")
|
||||||
|
self.assertEqual(bin(s), "78563412")
|
||||||
|
self.assertEqual(s.value, 0x12345678)
|
||||||
|
|
||||||
|
s = c_uint.__ctype_be__(0x12345678)
|
||||||
|
self.assertEqual(bin(struct.pack(">I", 0x12345678)), "12345678")
|
||||||
|
self.assertEqual(bin(s), "12345678")
|
||||||
|
self.assertEqual(s.value, 0x12345678)
|
||||||
|
|
||||||
|
s = c_uint.__ctype_le__(0x12345678)
|
||||||
|
self.assertEqual(bin(struct.pack("<I", 0x12345678)), "78563412")
|
||||||
|
self.assertEqual(bin(s), "78563412")
|
||||||
|
self.assertEqual(s.value, 0x12345678)
|
||||||
|
|
||||||
|
def test_endian_longlong(self):
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
self.assertIs(c_longlong.__ctype_le__, c_longlong)
|
||||||
|
self.assertIs(c_longlong.__ctype_be__.__ctype_le__, c_longlong)
|
||||||
|
else:
|
||||||
|
self.assertIs(c_longlong.__ctype_be__, c_longlong)
|
||||||
|
self.assertIs(c_longlong.__ctype_le__.__ctype_be__, c_longlong)
|
||||||
|
|
||||||
|
s = c_longlong.__ctype_be__(0x1234567890ABCDEF)
|
||||||
|
self.assertEqual(bin(struct.pack(">q", 0x1234567890ABCDEF)), "1234567890ABCDEF")
|
||||||
|
self.assertEqual(bin(s), "1234567890ABCDEF")
|
||||||
|
self.assertEqual(s.value, 0x1234567890ABCDEF)
|
||||||
|
|
||||||
|
s = c_longlong.__ctype_le__(0x1234567890ABCDEF)
|
||||||
|
self.assertEqual(bin(struct.pack("<q", 0x1234567890ABCDEF)), "EFCDAB9078563412")
|
||||||
|
self.assertEqual(bin(s), "EFCDAB9078563412")
|
||||||
|
self.assertEqual(s.value, 0x1234567890ABCDEF)
|
||||||
|
|
||||||
|
s = c_ulonglong.__ctype_be__(0x1234567890ABCDEF)
|
||||||
|
self.assertEqual(bin(struct.pack(">Q", 0x1234567890ABCDEF)), "1234567890ABCDEF")
|
||||||
|
self.assertEqual(bin(s), "1234567890ABCDEF")
|
||||||
|
self.assertEqual(s.value, 0x1234567890ABCDEF)
|
||||||
|
|
||||||
|
s = c_ulonglong.__ctype_le__(0x1234567890ABCDEF)
|
||||||
|
self.assertEqual(bin(struct.pack("<Q", 0x1234567890ABCDEF)), "EFCDAB9078563412")
|
||||||
|
self.assertEqual(bin(s), "EFCDAB9078563412")
|
||||||
|
self.assertEqual(s.value, 0x1234567890ABCDEF)
|
||||||
|
|
||||||
|
def test_endian_float(self):
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
self.assertIs(c_float.__ctype_le__, c_float)
|
||||||
|
self.assertIs(c_float.__ctype_be__.__ctype_le__, c_float)
|
||||||
|
else:
|
||||||
|
self.assertIs(c_float.__ctype_be__, c_float)
|
||||||
|
self.assertIs(c_float.__ctype_le__.__ctype_be__, c_float)
|
||||||
|
s = c_float(math.pi)
|
||||||
|
self.assertEqual(bin(struct.pack("f", math.pi)), bin(s))
|
||||||
|
# Hm, what's the precision of a float compared to a double?
|
||||||
|
self.assertAlmostEqual(s.value, math.pi, places=6)
|
||||||
|
s = c_float.__ctype_le__(math.pi)
|
||||||
|
self.assertAlmostEqual(s.value, math.pi, places=6)
|
||||||
|
self.assertEqual(bin(struct.pack("<f", math.pi)), bin(s))
|
||||||
|
s = c_float.__ctype_be__(math.pi)
|
||||||
|
self.assertAlmostEqual(s.value, math.pi, places=6)
|
||||||
|
self.assertEqual(bin(struct.pack(">f", math.pi)), bin(s))
|
||||||
|
|
||||||
|
def test_endian_double(self):
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
self.assertIs(c_double.__ctype_le__, c_double)
|
||||||
|
self.assertIs(c_double.__ctype_be__.__ctype_le__, c_double)
|
||||||
|
else:
|
||||||
|
self.assertIs(c_double.__ctype_be__, c_double)
|
||||||
|
self.assertIs(c_double.__ctype_le__.__ctype_be__, c_double)
|
||||||
|
s = c_double(math.pi)
|
||||||
|
self.assertEqual(s.value, math.pi)
|
||||||
|
self.assertEqual(bin(struct.pack("d", math.pi)), bin(s))
|
||||||
|
s = c_double.__ctype_le__(math.pi)
|
||||||
|
self.assertEqual(s.value, math.pi)
|
||||||
|
self.assertEqual(bin(struct.pack("<d", math.pi)), bin(s))
|
||||||
|
s = c_double.__ctype_be__(math.pi)
|
||||||
|
self.assertEqual(s.value, math.pi)
|
||||||
|
self.assertEqual(bin(struct.pack(">d", math.pi)), bin(s))
|
||||||
|
|
||||||
|
def test_endian_other(self):
|
||||||
|
self.assertIs(c_byte.__ctype_le__, c_byte)
|
||||||
|
self.assertIs(c_byte.__ctype_be__, c_byte)
|
||||||
|
|
||||||
|
self.assertIs(c_ubyte.__ctype_le__, c_ubyte)
|
||||||
|
self.assertIs(c_ubyte.__ctype_be__, c_ubyte)
|
||||||
|
|
||||||
|
self.assertIs(c_char.__ctype_le__, c_char)
|
||||||
|
self.assertIs(c_char.__ctype_be__, c_char)
|
||||||
|
|
||||||
|
def test_struct_fields_unsupported_byte_order(self):
|
||||||
|
|
||||||
|
fields = [
|
||||||
|
("a", c_ubyte),
|
||||||
|
("b", c_byte),
|
||||||
|
("c", c_short),
|
||||||
|
("d", c_ushort),
|
||||||
|
("e", c_int),
|
||||||
|
("f", c_uint),
|
||||||
|
("g", c_long),
|
||||||
|
("h", c_ulong),
|
||||||
|
("i", c_longlong),
|
||||||
|
("k", c_ulonglong),
|
||||||
|
("l", c_float),
|
||||||
|
("m", c_double),
|
||||||
|
("n", c_char),
|
||||||
|
("b1", c_byte, 3),
|
||||||
|
("b2", c_byte, 3),
|
||||||
|
("b3", c_byte, 2),
|
||||||
|
("a", c_int * 3 * 3 * 3)
|
||||||
|
]
|
||||||
|
|
||||||
|
# these fields do not support different byte order:
|
||||||
|
for typ in c_wchar, c_void_p, POINTER(c_int):
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
class T(BigEndianStructure if sys.byteorder == "little" else LittleEndianStructure):
|
||||||
|
_fields_ = fields + [("x", typ)]
|
||||||
|
|
||||||
|
|
||||||
|
def test_struct_struct(self):
|
||||||
|
# nested structures with different byteorders
|
||||||
|
|
||||||
|
# create nested structures with given byteorders and set memory to data
|
||||||
|
|
||||||
|
for nested, data in (
|
||||||
|
(BigEndianStructure, b'\0\0\0\1\0\0\0\2'),
|
||||||
|
(LittleEndianStructure, b'\1\0\0\0\2\0\0\0'),
|
||||||
|
):
|
||||||
|
for parent in (
|
||||||
|
BigEndianStructure,
|
||||||
|
LittleEndianStructure,
|
||||||
|
Structure,
|
||||||
|
):
|
||||||
|
class NestedStructure(nested):
|
||||||
|
_fields_ = [("x", c_uint32),
|
||||||
|
("y", c_uint32)]
|
||||||
|
|
||||||
|
class TestStructure(parent):
|
||||||
|
_fields_ = [("point", NestedStructure)]
|
||||||
|
|
||||||
|
self.assertEqual(len(data), sizeof(TestStructure))
|
||||||
|
ptr = POINTER(TestStructure)
|
||||||
|
s = cast(data, ptr)[0]
|
||||||
|
del ctypes._pointer_type_cache[TestStructure]
|
||||||
|
self.assertEqual(s.point.x, 1)
|
||||||
|
self.assertEqual(s.point.y, 2)
|
||||||
|
|
||||||
|
def test_struct_field_alignment(self):
|
||||||
|
# standard packing in struct uses no alignment.
|
||||||
|
# So, we have to align using pad bytes.
|
||||||
|
#
|
||||||
|
# Unaligned accesses will crash Python (on those platforms that
|
||||||
|
# don't allow it, like sparc solaris).
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
base = BigEndianStructure
|
||||||
|
fmt = ">bxhid"
|
||||||
|
else:
|
||||||
|
base = LittleEndianStructure
|
||||||
|
fmt = "<bxhid"
|
||||||
|
|
||||||
|
class S(base):
|
||||||
|
_fields_ = [("b", c_byte),
|
||||||
|
("h", c_short),
|
||||||
|
("i", c_int),
|
||||||
|
("d", c_double)]
|
||||||
|
|
||||||
|
s1 = S(0x12, 0x1234, 0x12345678, 3.14)
|
||||||
|
s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
|
||||||
|
self.assertEqual(bin(s1), bin(s2))
|
||||||
|
|
||||||
|
def test_unaligned_nonnative_struct_fields(self):
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
base = BigEndianStructure
|
||||||
|
fmt = ">b h xi xd"
|
||||||
|
else:
|
||||||
|
base = LittleEndianStructure
|
||||||
|
fmt = "<b h xi xd"
|
||||||
|
|
||||||
|
class S(base):
|
||||||
|
_pack_ = 1
|
||||||
|
_fields_ = [("b", c_byte),
|
||||||
|
("h", c_short),
|
||||||
|
|
||||||
|
("_1", c_byte),
|
||||||
|
("i", c_int),
|
||||||
|
|
||||||
|
("_2", c_byte),
|
||||||
|
("d", c_double)]
|
||||||
|
|
||||||
|
s1 = S()
|
||||||
|
s1.b = 0x12
|
||||||
|
s1.h = 0x1234
|
||||||
|
s1.i = 0x12345678
|
||||||
|
s1.d = 3.14
|
||||||
|
s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
|
||||||
|
self.assertEqual(bin(s1), bin(s2))
|
||||||
|
|
||||||
|
def test_unaligned_native_struct_fields(self):
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
fmt = "<b h xi xd"
|
||||||
|
else:
|
||||||
|
base = LittleEndianStructure
|
||||||
|
fmt = ">b h xi xd"
|
||||||
|
|
||||||
|
class S(Structure):
|
||||||
|
_pack_ = 1
|
||||||
|
_fields_ = [("b", c_byte),
|
||||||
|
|
||||||
|
("h", c_short),
|
||||||
|
|
||||||
|
("_1", c_byte),
|
||||||
|
("i", c_int),
|
||||||
|
|
||||||
|
("_2", c_byte),
|
||||||
|
("d", c_double)]
|
||||||
|
|
||||||
|
s1 = S()
|
||||||
|
s1.b = 0x12
|
||||||
|
s1.h = 0x1234
|
||||||
|
s1.i = 0x12345678
|
||||||
|
s1.d = 3.14
|
||||||
|
s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
|
||||||
|
self.assertEqual(bin(s1), bin(s2))
|
||||||
|
|
||||||
|
def test_union_fields_unsupported_byte_order(self):
|
||||||
|
|
||||||
|
fields = [
|
||||||
|
("a", c_ubyte),
|
||||||
|
("b", c_byte),
|
||||||
|
("c", c_short),
|
||||||
|
("d", c_ushort),
|
||||||
|
("e", c_int),
|
||||||
|
("f", c_uint),
|
||||||
|
("g", c_long),
|
||||||
|
("h", c_ulong),
|
||||||
|
("i", c_longlong),
|
||||||
|
("k", c_ulonglong),
|
||||||
|
("l", c_float),
|
||||||
|
("m", c_double),
|
||||||
|
("n", c_char),
|
||||||
|
("b1", c_byte, 3),
|
||||||
|
("b2", c_byte, 3),
|
||||||
|
("b3", c_byte, 2),
|
||||||
|
("a", c_int * 3 * 3 * 3)
|
||||||
|
]
|
||||||
|
|
||||||
|
# these fields do not support different byte order:
|
||||||
|
for typ in c_wchar, c_void_p, POINTER(c_int):
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
class T(BigEndianUnion if sys.byteorder == "little" else LittleEndianUnion):
|
||||||
|
_fields_ = fields + [("x", typ)]
|
||||||
|
|
||||||
|
def test_union_struct(self):
|
||||||
|
# nested structures in unions with different byteorders
|
||||||
|
|
||||||
|
# create nested structures in unions with given byteorders and set memory to data
|
||||||
|
|
||||||
|
for nested, data in (
|
||||||
|
(BigEndianStructure, b'\0\0\0\1\0\0\0\2'),
|
||||||
|
(LittleEndianStructure, b'\1\0\0\0\2\0\0\0'),
|
||||||
|
):
|
||||||
|
for parent in (
|
||||||
|
BigEndianUnion,
|
||||||
|
LittleEndianUnion,
|
||||||
|
Union,
|
||||||
|
):
|
||||||
|
class NestedStructure(nested):
|
||||||
|
_fields_ = [("x", c_uint32),
|
||||||
|
("y", c_uint32)]
|
||||||
|
|
||||||
|
class TestUnion(parent):
|
||||||
|
_fields_ = [("point", NestedStructure)]
|
||||||
|
|
||||||
|
self.assertEqual(len(data), sizeof(TestUnion))
|
||||||
|
ptr = POINTER(TestUnion)
|
||||||
|
s = cast(data, ptr)[0]
|
||||||
|
del ctypes._pointer_type_cache[TestUnion]
|
||||||
|
self.assertEqual(s.point.x, 1)
|
||||||
|
self.assertEqual(s.point.y, 2)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
333
Lib/ctypes/test/test_callbacks.py
vendored
Normal file
333
Lib/ctypes/test/test_callbacks.py
vendored
Normal file
@@ -0,0 +1,333 @@
|
|||||||
|
import functools
|
||||||
|
import unittest
|
||||||
|
from test import support
|
||||||
|
|
||||||
|
from ctypes import *
|
||||||
|
from ctypes.test import need_symbol
|
||||||
|
from _ctypes import CTYPES_MAX_ARGCOUNT
|
||||||
|
import _ctypes_test
|
||||||
|
|
||||||
|
class Callbacks(unittest.TestCase):
|
||||||
|
functype = CFUNCTYPE
|
||||||
|
|
||||||
|
## def tearDown(self):
|
||||||
|
## import gc
|
||||||
|
## gc.collect()
|
||||||
|
|
||||||
|
def callback(self, *args):
|
||||||
|
self.got_args = args
|
||||||
|
return args[-1]
|
||||||
|
|
||||||
|
def check_type(self, typ, arg):
|
||||||
|
PROTO = self.functype.__func__(typ, typ)
|
||||||
|
result = PROTO(self.callback)(arg)
|
||||||
|
if typ == c_float:
|
||||||
|
self.assertAlmostEqual(result, arg, places=5)
|
||||||
|
else:
|
||||||
|
self.assertEqual(self.got_args, (arg,))
|
||||||
|
self.assertEqual(result, arg)
|
||||||
|
|
||||||
|
PROTO = self.functype.__func__(typ, c_byte, typ)
|
||||||
|
result = PROTO(self.callback)(-3, arg)
|
||||||
|
if typ == c_float:
|
||||||
|
self.assertAlmostEqual(result, arg, places=5)
|
||||||
|
else:
|
||||||
|
self.assertEqual(self.got_args, (-3, arg))
|
||||||
|
self.assertEqual(result, arg)
|
||||||
|
|
||||||
|
################
|
||||||
|
|
||||||
|
def test_byte(self):
|
||||||
|
self.check_type(c_byte, 42)
|
||||||
|
self.check_type(c_byte, -42)
|
||||||
|
|
||||||
|
def test_ubyte(self):
|
||||||
|
self.check_type(c_ubyte, 42)
|
||||||
|
|
||||||
|
def test_short(self):
|
||||||
|
self.check_type(c_short, 42)
|
||||||
|
self.check_type(c_short, -42)
|
||||||
|
|
||||||
|
def test_ushort(self):
|
||||||
|
self.check_type(c_ushort, 42)
|
||||||
|
|
||||||
|
def test_int(self):
|
||||||
|
self.check_type(c_int, 42)
|
||||||
|
self.check_type(c_int, -42)
|
||||||
|
|
||||||
|
def test_uint(self):
|
||||||
|
self.check_type(c_uint, 42)
|
||||||
|
|
||||||
|
def test_long(self):
|
||||||
|
self.check_type(c_long, 42)
|
||||||
|
self.check_type(c_long, -42)
|
||||||
|
|
||||||
|
def test_ulong(self):
|
||||||
|
self.check_type(c_ulong, 42)
|
||||||
|
|
||||||
|
@need_symbol('c_longlong')
|
||||||
|
def test_longlong(self):
|
||||||
|
self.check_type(c_longlong, 42)
|
||||||
|
self.check_type(c_longlong, -42)
|
||||||
|
|
||||||
|
@need_symbol('c_ulonglong')
|
||||||
|
def test_ulonglong(self):
|
||||||
|
self.check_type(c_ulonglong, 42)
|
||||||
|
|
||||||
|
def test_float(self):
|
||||||
|
# only almost equal: double -> float -> double
|
||||||
|
import math
|
||||||
|
self.check_type(c_float, math.e)
|
||||||
|
self.check_type(c_float, -math.e)
|
||||||
|
|
||||||
|
def test_double(self):
|
||||||
|
self.check_type(c_double, 3.14)
|
||||||
|
self.check_type(c_double, -3.14)
|
||||||
|
|
||||||
|
@need_symbol('c_longdouble')
|
||||||
|
def test_longdouble(self):
|
||||||
|
self.check_type(c_longdouble, 3.14)
|
||||||
|
self.check_type(c_longdouble, -3.14)
|
||||||
|
|
||||||
|
def test_char(self):
|
||||||
|
self.check_type(c_char, b"x")
|
||||||
|
self.check_type(c_char, b"a")
|
||||||
|
|
||||||
|
# disabled: would now (correctly) raise a RuntimeWarning about
|
||||||
|
# a memory leak. A callback function cannot return a non-integral
|
||||||
|
# C type without causing a memory leak.
|
||||||
|
@unittest.skip('test disabled')
|
||||||
|
def test_char_p(self):
|
||||||
|
self.check_type(c_char_p, "abc")
|
||||||
|
self.check_type(c_char_p, "def")
|
||||||
|
|
||||||
|
def test_pyobject(self):
|
||||||
|
o = ()
|
||||||
|
from sys import getrefcount as grc
|
||||||
|
for o in (), [], object():
|
||||||
|
initial = grc(o)
|
||||||
|
# This call leaks a reference to 'o'...
|
||||||
|
self.check_type(py_object, o)
|
||||||
|
before = grc(o)
|
||||||
|
# ...but this call doesn't leak any more. Where is the refcount?
|
||||||
|
self.check_type(py_object, o)
|
||||||
|
after = grc(o)
|
||||||
|
self.assertEqual((after, o), (before, o))
|
||||||
|
|
||||||
|
def test_unsupported_restype_1(self):
|
||||||
|
# Only "fundamental" result types are supported for callback
|
||||||
|
# functions, the type must have a non-NULL stgdict->setfunc.
|
||||||
|
# POINTER(c_double), for example, is not supported.
|
||||||
|
|
||||||
|
prototype = self.functype.__func__(POINTER(c_double))
|
||||||
|
# The type is checked when the prototype is called
|
||||||
|
self.assertRaises(TypeError, prototype, lambda: None)
|
||||||
|
|
||||||
|
def test_unsupported_restype_2(self):
|
||||||
|
prototype = self.functype.__func__(object)
|
||||||
|
self.assertRaises(TypeError, prototype, lambda: None)
|
||||||
|
|
||||||
|
def test_issue_7959(self):
|
||||||
|
proto = self.functype.__func__(None)
|
||||||
|
|
||||||
|
class X(object):
|
||||||
|
def func(self): pass
|
||||||
|
def __init__(self):
|
||||||
|
self.v = proto(self.func)
|
||||||
|
|
||||||
|
import gc
|
||||||
|
for i in range(32):
|
||||||
|
X()
|
||||||
|
gc.collect()
|
||||||
|
live = [x for x in gc.get_objects()
|
||||||
|
if isinstance(x, X)]
|
||||||
|
self.assertEqual(len(live), 0)
|
||||||
|
|
||||||
|
def test_issue12483(self):
|
||||||
|
import gc
|
||||||
|
class Nasty:
|
||||||
|
def __del__(self):
|
||||||
|
gc.collect()
|
||||||
|
CFUNCTYPE(None)(lambda x=Nasty(): None)
|
||||||
|
|
||||||
|
|
||||||
|
@need_symbol('WINFUNCTYPE')
|
||||||
|
class StdcallCallbacks(Callbacks):
|
||||||
|
try:
|
||||||
|
functype = WINFUNCTYPE
|
||||||
|
except NameError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
class SampleCallbacksTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_integrate(self):
|
||||||
|
# Derived from some then non-working code, posted by David Foster
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
|
||||||
|
# The function prototype called by 'integrate': double func(double);
|
||||||
|
CALLBACK = CFUNCTYPE(c_double, c_double)
|
||||||
|
|
||||||
|
# The integrate function itself, exposed from the _ctypes_test dll
|
||||||
|
integrate = dll.integrate
|
||||||
|
integrate.argtypes = (c_double, c_double, CALLBACK, c_long)
|
||||||
|
integrate.restype = c_double
|
||||||
|
|
||||||
|
def func(x):
|
||||||
|
return x**2
|
||||||
|
|
||||||
|
result = integrate(0.0, 1.0, CALLBACK(func), 10)
|
||||||
|
diff = abs(result - 1./3.)
|
||||||
|
|
||||||
|
self.assertLess(diff, 0.01, "%s not less than 0.01" % diff)
|
||||||
|
|
||||||
|
def test_issue_8959_a(self):
|
||||||
|
from ctypes.util import find_library
|
||||||
|
libc_path = find_library("c")
|
||||||
|
if not libc_path:
|
||||||
|
self.skipTest('could not find libc')
|
||||||
|
libc = CDLL(libc_path)
|
||||||
|
|
||||||
|
@CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
|
||||||
|
def cmp_func(a, b):
|
||||||
|
return a[0] - b[0]
|
||||||
|
|
||||||
|
array = (c_int * 5)(5, 1, 99, 7, 33)
|
||||||
|
|
||||||
|
libc.qsort(array, len(array), sizeof(c_int), cmp_func)
|
||||||
|
self.assertEqual(array[:], [1, 5, 7, 33, 99])
|
||||||
|
|
||||||
|
@need_symbol('WINFUNCTYPE')
|
||||||
|
def test_issue_8959_b(self):
|
||||||
|
from ctypes.wintypes import BOOL, HWND, LPARAM
|
||||||
|
global windowCount
|
||||||
|
windowCount = 0
|
||||||
|
|
||||||
|
@WINFUNCTYPE(BOOL, HWND, LPARAM)
|
||||||
|
def EnumWindowsCallbackFunc(hwnd, lParam):
|
||||||
|
global windowCount
|
||||||
|
windowCount += 1
|
||||||
|
return True #Allow windows to keep enumerating
|
||||||
|
|
||||||
|
windll.user32.EnumWindows(EnumWindowsCallbackFunc, 0)
|
||||||
|
|
||||||
|
def test_callback_register_int(self):
|
||||||
|
# Issue #8275: buggy handling of callback args under Win64
|
||||||
|
# NOTE: should be run on release builds as well
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
CALLBACK = CFUNCTYPE(c_int, c_int, c_int, c_int, c_int, c_int)
|
||||||
|
# All this function does is call the callback with its args squared
|
||||||
|
func = dll._testfunc_cbk_reg_int
|
||||||
|
func.argtypes = (c_int, c_int, c_int, c_int, c_int, CALLBACK)
|
||||||
|
func.restype = c_int
|
||||||
|
|
||||||
|
def callback(a, b, c, d, e):
|
||||||
|
return a + b + c + d + e
|
||||||
|
|
||||||
|
result = func(2, 3, 4, 5, 6, CALLBACK(callback))
|
||||||
|
self.assertEqual(result, callback(2*2, 3*3, 4*4, 5*5, 6*6))
|
||||||
|
|
||||||
|
def test_callback_register_double(self):
|
||||||
|
# Issue #8275: buggy handling of callback args under Win64
|
||||||
|
# NOTE: should be run on release builds as well
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
CALLBACK = CFUNCTYPE(c_double, c_double, c_double, c_double,
|
||||||
|
c_double, c_double)
|
||||||
|
# All this function does is call the callback with its args squared
|
||||||
|
func = dll._testfunc_cbk_reg_double
|
||||||
|
func.argtypes = (c_double, c_double, c_double,
|
||||||
|
c_double, c_double, CALLBACK)
|
||||||
|
func.restype = c_double
|
||||||
|
|
||||||
|
def callback(a, b, c, d, e):
|
||||||
|
return a + b + c + d + e
|
||||||
|
|
||||||
|
result = func(1.1, 2.2, 3.3, 4.4, 5.5, CALLBACK(callback))
|
||||||
|
self.assertEqual(result,
|
||||||
|
callback(1.1*1.1, 2.2*2.2, 3.3*3.3, 4.4*4.4, 5.5*5.5))
|
||||||
|
|
||||||
|
def test_callback_large_struct(self):
|
||||||
|
class Check: pass
|
||||||
|
|
||||||
|
# This should mirror the structure in Modules/_ctypes/_ctypes_test.c
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [
|
||||||
|
('first', c_ulong),
|
||||||
|
('second', c_ulong),
|
||||||
|
('third', c_ulong),
|
||||||
|
]
|
||||||
|
|
||||||
|
def callback(check, s):
|
||||||
|
check.first = s.first
|
||||||
|
check.second = s.second
|
||||||
|
check.third = s.third
|
||||||
|
# See issue #29565.
|
||||||
|
# The structure should be passed by value, so
|
||||||
|
# any changes to it should not be reflected in
|
||||||
|
# the value passed
|
||||||
|
s.first = s.second = s.third = 0x0badf00d
|
||||||
|
|
||||||
|
check = Check()
|
||||||
|
s = X()
|
||||||
|
s.first = 0xdeadbeef
|
||||||
|
s.second = 0xcafebabe
|
||||||
|
s.third = 0x0bad1dea
|
||||||
|
|
||||||
|
CALLBACK = CFUNCTYPE(None, X)
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
func = dll._testfunc_cbk_large_struct
|
||||||
|
func.argtypes = (X, CALLBACK)
|
||||||
|
func.restype = None
|
||||||
|
# the function just calls the callback with the passed structure
|
||||||
|
func(s, CALLBACK(functools.partial(callback, check)))
|
||||||
|
self.assertEqual(check.first, s.first)
|
||||||
|
self.assertEqual(check.second, s.second)
|
||||||
|
self.assertEqual(check.third, s.third)
|
||||||
|
self.assertEqual(check.first, 0xdeadbeef)
|
||||||
|
self.assertEqual(check.second, 0xcafebabe)
|
||||||
|
self.assertEqual(check.third, 0x0bad1dea)
|
||||||
|
# See issue #29565.
|
||||||
|
# Ensure that the original struct is unchanged.
|
||||||
|
self.assertEqual(s.first, check.first)
|
||||||
|
self.assertEqual(s.second, check.second)
|
||||||
|
self.assertEqual(s.third, check.third)
|
||||||
|
|
||||||
|
def test_callback_too_many_args(self):
|
||||||
|
def func(*args):
|
||||||
|
return len(args)
|
||||||
|
|
||||||
|
# valid call with nargs <= CTYPES_MAX_ARGCOUNT
|
||||||
|
proto = CFUNCTYPE(c_int, *(c_int,) * CTYPES_MAX_ARGCOUNT)
|
||||||
|
cb = proto(func)
|
||||||
|
args1 = (1,) * CTYPES_MAX_ARGCOUNT
|
||||||
|
self.assertEqual(cb(*args1), CTYPES_MAX_ARGCOUNT)
|
||||||
|
|
||||||
|
# invalid call with nargs > CTYPES_MAX_ARGCOUNT
|
||||||
|
args2 = (1,) * (CTYPES_MAX_ARGCOUNT + 1)
|
||||||
|
with self.assertRaises(ArgumentError):
|
||||||
|
cb(*args2)
|
||||||
|
|
||||||
|
# error when creating the type with too many arguments
|
||||||
|
with self.assertRaises(ArgumentError):
|
||||||
|
CFUNCTYPE(c_int, *(c_int,) * (CTYPES_MAX_ARGCOUNT + 1))
|
||||||
|
|
||||||
|
def test_convert_result_error(self):
|
||||||
|
def func():
|
||||||
|
return ("tuple",)
|
||||||
|
|
||||||
|
proto = CFUNCTYPE(c_int)
|
||||||
|
ctypes_func = proto(func)
|
||||||
|
with support.catch_unraisable_exception() as cm:
|
||||||
|
# don't test the result since it is an uninitialized value
|
||||||
|
result = ctypes_func()
|
||||||
|
|
||||||
|
self.assertIsInstance(cm.unraisable.exc_value, TypeError)
|
||||||
|
self.assertEqual(cm.unraisable.err_msg,
|
||||||
|
"Exception ignored on converting result "
|
||||||
|
"of ctypes callback function")
|
||||||
|
self.assertIs(cm.unraisable.object, func)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
99
Lib/ctypes/test/test_cast.py
vendored
Normal file
99
Lib/ctypes/test/test_cast.py
vendored
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
from ctypes import *
|
||||||
|
from ctypes.test import need_symbol
|
||||||
|
import unittest
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_array2pointer(self):
|
||||||
|
array = (c_int * 3)(42, 17, 2)
|
||||||
|
|
||||||
|
# casting an array to a pointer works.
|
||||||
|
ptr = cast(array, POINTER(c_int))
|
||||||
|
self.assertEqual([ptr[i] for i in range(3)], [42, 17, 2])
|
||||||
|
|
||||||
|
if 2*sizeof(c_short) == sizeof(c_int):
|
||||||
|
ptr = cast(array, POINTER(c_short))
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
self.assertEqual([ptr[i] for i in range(6)],
|
||||||
|
[42, 0, 17, 0, 2, 0])
|
||||||
|
else:
|
||||||
|
self.assertEqual([ptr[i] for i in range(6)],
|
||||||
|
[0, 42, 0, 17, 0, 2])
|
||||||
|
|
||||||
|
def test_address2pointer(self):
|
||||||
|
array = (c_int * 3)(42, 17, 2)
|
||||||
|
|
||||||
|
address = addressof(array)
|
||||||
|
ptr = cast(c_void_p(address), POINTER(c_int))
|
||||||
|
self.assertEqual([ptr[i] for i in range(3)], [42, 17, 2])
|
||||||
|
|
||||||
|
ptr = cast(address, POINTER(c_int))
|
||||||
|
self.assertEqual([ptr[i] for i in range(3)], [42, 17, 2])
|
||||||
|
|
||||||
|
def test_p2a_objects(self):
|
||||||
|
array = (c_char_p * 5)()
|
||||||
|
self.assertEqual(array._objects, None)
|
||||||
|
array[0] = b"foo bar"
|
||||||
|
self.assertEqual(array._objects, {'0': b"foo bar"})
|
||||||
|
|
||||||
|
p = cast(array, POINTER(c_char_p))
|
||||||
|
# array and p share a common _objects attribute
|
||||||
|
self.assertIs(p._objects, array._objects)
|
||||||
|
self.assertEqual(array._objects, {'0': b"foo bar", id(array): array})
|
||||||
|
p[0] = b"spam spam"
|
||||||
|
self.assertEqual(p._objects, {'0': b"spam spam", id(array): array})
|
||||||
|
self.assertIs(array._objects, p._objects)
|
||||||
|
p[1] = b"foo bar"
|
||||||
|
self.assertEqual(p._objects, {'1': b'foo bar', '0': b"spam spam", id(array): array})
|
||||||
|
self.assertIs(array._objects, p._objects)
|
||||||
|
|
||||||
|
def test_other(self):
|
||||||
|
p = cast((c_int * 4)(1, 2, 3, 4), POINTER(c_int))
|
||||||
|
self.assertEqual(p[:4], [1,2, 3, 4])
|
||||||
|
self.assertEqual(p[:4:], [1, 2, 3, 4])
|
||||||
|
self.assertEqual(p[3:-1:-1], [4, 3, 2, 1])
|
||||||
|
self.assertEqual(p[:4:3], [1, 4])
|
||||||
|
c_int()
|
||||||
|
self.assertEqual(p[:4], [1, 2, 3, 4])
|
||||||
|
self.assertEqual(p[:4:], [1, 2, 3, 4])
|
||||||
|
self.assertEqual(p[3:-1:-1], [4, 3, 2, 1])
|
||||||
|
self.assertEqual(p[:4:3], [1, 4])
|
||||||
|
p[2] = 96
|
||||||
|
self.assertEqual(p[:4], [1, 2, 96, 4])
|
||||||
|
self.assertEqual(p[:4:], [1, 2, 96, 4])
|
||||||
|
self.assertEqual(p[3:-1:-1], [4, 96, 2, 1])
|
||||||
|
self.assertEqual(p[:4:3], [1, 4])
|
||||||
|
c_int()
|
||||||
|
self.assertEqual(p[:4], [1, 2, 96, 4])
|
||||||
|
self.assertEqual(p[:4:], [1, 2, 96, 4])
|
||||||
|
self.assertEqual(p[3:-1:-1], [4, 96, 2, 1])
|
||||||
|
self.assertEqual(p[:4:3], [1, 4])
|
||||||
|
|
||||||
|
def test_char_p(self):
|
||||||
|
# This didn't work: bad argument to internal function
|
||||||
|
s = c_char_p(b"hiho")
|
||||||
|
self.assertEqual(cast(cast(s, c_void_p), c_char_p).value,
|
||||||
|
b"hiho")
|
||||||
|
|
||||||
|
@need_symbol('c_wchar_p')
|
||||||
|
def test_wchar_p(self):
|
||||||
|
s = c_wchar_p("hiho")
|
||||||
|
self.assertEqual(cast(cast(s, c_void_p), c_wchar_p).value,
|
||||||
|
"hiho")
|
||||||
|
|
||||||
|
def test_bad_type_arg(self):
|
||||||
|
# The type argument must be a ctypes pointer type.
|
||||||
|
array_type = c_byte * sizeof(c_int)
|
||||||
|
array = array_type()
|
||||||
|
self.assertRaises(TypeError, cast, array, None)
|
||||||
|
self.assertRaises(TypeError, cast, array, array_type)
|
||||||
|
class Struct(Structure):
|
||||||
|
_fields_ = [("a", c_int)]
|
||||||
|
self.assertRaises(TypeError, cast, array, Struct)
|
||||||
|
class MyUnion(Union):
|
||||||
|
_fields_ = [("a", c_int)]
|
||||||
|
self.assertRaises(TypeError, cast, array, MyUnion)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
218
Lib/ctypes/test/test_cfuncs.py
vendored
Normal file
218
Lib/ctypes/test/test_cfuncs.py
vendored
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
# A lot of failures in these tests on Mac OS X.
|
||||||
|
# Byte order related?
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from ctypes import *
|
||||||
|
from ctypes.test import need_symbol
|
||||||
|
|
||||||
|
import _ctypes_test
|
||||||
|
|
||||||
|
class CFunctions(unittest.TestCase):
|
||||||
|
_dll = CDLL(_ctypes_test.__file__)
|
||||||
|
|
||||||
|
def S(self):
|
||||||
|
return c_longlong.in_dll(self._dll, "last_tf_arg_s").value
|
||||||
|
def U(self):
|
||||||
|
return c_ulonglong.in_dll(self._dll, "last_tf_arg_u").value
|
||||||
|
|
||||||
|
def test_byte(self):
|
||||||
|
self._dll.tf_b.restype = c_byte
|
||||||
|
self._dll.tf_b.argtypes = (c_byte,)
|
||||||
|
self.assertEqual(self._dll.tf_b(-126), -42)
|
||||||
|
self.assertEqual(self.S(), -126)
|
||||||
|
|
||||||
|
def test_byte_plus(self):
|
||||||
|
self._dll.tf_bb.restype = c_byte
|
||||||
|
self._dll.tf_bb.argtypes = (c_byte, c_byte)
|
||||||
|
self.assertEqual(self._dll.tf_bb(0, -126), -42)
|
||||||
|
self.assertEqual(self.S(), -126)
|
||||||
|
|
||||||
|
def test_ubyte(self):
|
||||||
|
self._dll.tf_B.restype = c_ubyte
|
||||||
|
self._dll.tf_B.argtypes = (c_ubyte,)
|
||||||
|
self.assertEqual(self._dll.tf_B(255), 85)
|
||||||
|
self.assertEqual(self.U(), 255)
|
||||||
|
|
||||||
|
def test_ubyte_plus(self):
|
||||||
|
self._dll.tf_bB.restype = c_ubyte
|
||||||
|
self._dll.tf_bB.argtypes = (c_byte, c_ubyte)
|
||||||
|
self.assertEqual(self._dll.tf_bB(0, 255), 85)
|
||||||
|
self.assertEqual(self.U(), 255)
|
||||||
|
|
||||||
|
def test_short(self):
|
||||||
|
self._dll.tf_h.restype = c_short
|
||||||
|
self._dll.tf_h.argtypes = (c_short,)
|
||||||
|
self.assertEqual(self._dll.tf_h(-32766), -10922)
|
||||||
|
self.assertEqual(self.S(), -32766)
|
||||||
|
|
||||||
|
def test_short_plus(self):
|
||||||
|
self._dll.tf_bh.restype = c_short
|
||||||
|
self._dll.tf_bh.argtypes = (c_byte, c_short)
|
||||||
|
self.assertEqual(self._dll.tf_bh(0, -32766), -10922)
|
||||||
|
self.assertEqual(self.S(), -32766)
|
||||||
|
|
||||||
|
def test_ushort(self):
|
||||||
|
self._dll.tf_H.restype = c_ushort
|
||||||
|
self._dll.tf_H.argtypes = (c_ushort,)
|
||||||
|
self.assertEqual(self._dll.tf_H(65535), 21845)
|
||||||
|
self.assertEqual(self.U(), 65535)
|
||||||
|
|
||||||
|
def test_ushort_plus(self):
|
||||||
|
self._dll.tf_bH.restype = c_ushort
|
||||||
|
self._dll.tf_bH.argtypes = (c_byte, c_ushort)
|
||||||
|
self.assertEqual(self._dll.tf_bH(0, 65535), 21845)
|
||||||
|
self.assertEqual(self.U(), 65535)
|
||||||
|
|
||||||
|
def test_int(self):
|
||||||
|
self._dll.tf_i.restype = c_int
|
||||||
|
self._dll.tf_i.argtypes = (c_int,)
|
||||||
|
self.assertEqual(self._dll.tf_i(-2147483646), -715827882)
|
||||||
|
self.assertEqual(self.S(), -2147483646)
|
||||||
|
|
||||||
|
def test_int_plus(self):
|
||||||
|
self._dll.tf_bi.restype = c_int
|
||||||
|
self._dll.tf_bi.argtypes = (c_byte, c_int)
|
||||||
|
self.assertEqual(self._dll.tf_bi(0, -2147483646), -715827882)
|
||||||
|
self.assertEqual(self.S(), -2147483646)
|
||||||
|
|
||||||
|
def test_uint(self):
|
||||||
|
self._dll.tf_I.restype = c_uint
|
||||||
|
self._dll.tf_I.argtypes = (c_uint,)
|
||||||
|
self.assertEqual(self._dll.tf_I(4294967295), 1431655765)
|
||||||
|
self.assertEqual(self.U(), 4294967295)
|
||||||
|
|
||||||
|
def test_uint_plus(self):
|
||||||
|
self._dll.tf_bI.restype = c_uint
|
||||||
|
self._dll.tf_bI.argtypes = (c_byte, c_uint)
|
||||||
|
self.assertEqual(self._dll.tf_bI(0, 4294967295), 1431655765)
|
||||||
|
self.assertEqual(self.U(), 4294967295)
|
||||||
|
|
||||||
|
def test_long(self):
|
||||||
|
self._dll.tf_l.restype = c_long
|
||||||
|
self._dll.tf_l.argtypes = (c_long,)
|
||||||
|
self.assertEqual(self._dll.tf_l(-2147483646), -715827882)
|
||||||
|
self.assertEqual(self.S(), -2147483646)
|
||||||
|
|
||||||
|
def test_long_plus(self):
|
||||||
|
self._dll.tf_bl.restype = c_long
|
||||||
|
self._dll.tf_bl.argtypes = (c_byte, c_long)
|
||||||
|
self.assertEqual(self._dll.tf_bl(0, -2147483646), -715827882)
|
||||||
|
self.assertEqual(self.S(), -2147483646)
|
||||||
|
|
||||||
|
def test_ulong(self):
|
||||||
|
self._dll.tf_L.restype = c_ulong
|
||||||
|
self._dll.tf_L.argtypes = (c_ulong,)
|
||||||
|
self.assertEqual(self._dll.tf_L(4294967295), 1431655765)
|
||||||
|
self.assertEqual(self.U(), 4294967295)
|
||||||
|
|
||||||
|
def test_ulong_plus(self):
|
||||||
|
self._dll.tf_bL.restype = c_ulong
|
||||||
|
self._dll.tf_bL.argtypes = (c_char, c_ulong)
|
||||||
|
self.assertEqual(self._dll.tf_bL(b' ', 4294967295), 1431655765)
|
||||||
|
self.assertEqual(self.U(), 4294967295)
|
||||||
|
|
||||||
|
@need_symbol('c_longlong')
|
||||||
|
def test_longlong(self):
|
||||||
|
self._dll.tf_q.restype = c_longlong
|
||||||
|
self._dll.tf_q.argtypes = (c_longlong, )
|
||||||
|
self.assertEqual(self._dll.tf_q(-9223372036854775806), -3074457345618258602)
|
||||||
|
self.assertEqual(self.S(), -9223372036854775806)
|
||||||
|
|
||||||
|
@need_symbol('c_longlong')
|
||||||
|
def test_longlong_plus(self):
|
||||||
|
self._dll.tf_bq.restype = c_longlong
|
||||||
|
self._dll.tf_bq.argtypes = (c_byte, c_longlong)
|
||||||
|
self.assertEqual(self._dll.tf_bq(0, -9223372036854775806), -3074457345618258602)
|
||||||
|
self.assertEqual(self.S(), -9223372036854775806)
|
||||||
|
|
||||||
|
@need_symbol('c_ulonglong')
|
||||||
|
def test_ulonglong(self):
|
||||||
|
self._dll.tf_Q.restype = c_ulonglong
|
||||||
|
self._dll.tf_Q.argtypes = (c_ulonglong, )
|
||||||
|
self.assertEqual(self._dll.tf_Q(18446744073709551615), 6148914691236517205)
|
||||||
|
self.assertEqual(self.U(), 18446744073709551615)
|
||||||
|
|
||||||
|
@need_symbol('c_ulonglong')
|
||||||
|
def test_ulonglong_plus(self):
|
||||||
|
self._dll.tf_bQ.restype = c_ulonglong
|
||||||
|
self._dll.tf_bQ.argtypes = (c_byte, c_ulonglong)
|
||||||
|
self.assertEqual(self._dll.tf_bQ(0, 18446744073709551615), 6148914691236517205)
|
||||||
|
self.assertEqual(self.U(), 18446744073709551615)
|
||||||
|
|
||||||
|
def test_float(self):
|
||||||
|
self._dll.tf_f.restype = c_float
|
||||||
|
self._dll.tf_f.argtypes = (c_float,)
|
||||||
|
self.assertEqual(self._dll.tf_f(-42.), -14.)
|
||||||
|
self.assertEqual(self.S(), -42)
|
||||||
|
|
||||||
|
def test_float_plus(self):
|
||||||
|
self._dll.tf_bf.restype = c_float
|
||||||
|
self._dll.tf_bf.argtypes = (c_byte, c_float)
|
||||||
|
self.assertEqual(self._dll.tf_bf(0, -42.), -14.)
|
||||||
|
self.assertEqual(self.S(), -42)
|
||||||
|
|
||||||
|
def test_double(self):
|
||||||
|
self._dll.tf_d.restype = c_double
|
||||||
|
self._dll.tf_d.argtypes = (c_double,)
|
||||||
|
self.assertEqual(self._dll.tf_d(42.), 14.)
|
||||||
|
self.assertEqual(self.S(), 42)
|
||||||
|
|
||||||
|
def test_double_plus(self):
|
||||||
|
self._dll.tf_bd.restype = c_double
|
||||||
|
self._dll.tf_bd.argtypes = (c_byte, c_double)
|
||||||
|
self.assertEqual(self._dll.tf_bd(0, 42.), 14.)
|
||||||
|
self.assertEqual(self.S(), 42)
|
||||||
|
|
||||||
|
@need_symbol('c_longdouble')
|
||||||
|
def test_longdouble(self):
|
||||||
|
self._dll.tf_D.restype = c_longdouble
|
||||||
|
self._dll.tf_D.argtypes = (c_longdouble,)
|
||||||
|
self.assertEqual(self._dll.tf_D(42.), 14.)
|
||||||
|
self.assertEqual(self.S(), 42)
|
||||||
|
|
||||||
|
@need_symbol('c_longdouble')
|
||||||
|
def test_longdouble_plus(self):
|
||||||
|
self._dll.tf_bD.restype = c_longdouble
|
||||||
|
self._dll.tf_bD.argtypes = (c_byte, c_longdouble)
|
||||||
|
self.assertEqual(self._dll.tf_bD(0, 42.), 14.)
|
||||||
|
self.assertEqual(self.S(), 42)
|
||||||
|
|
||||||
|
def test_callwithresult(self):
|
||||||
|
def process_result(result):
|
||||||
|
return result * 2
|
||||||
|
self._dll.tf_i.restype = process_result
|
||||||
|
self._dll.tf_i.argtypes = (c_int,)
|
||||||
|
self.assertEqual(self._dll.tf_i(42), 28)
|
||||||
|
self.assertEqual(self.S(), 42)
|
||||||
|
self.assertEqual(self._dll.tf_i(-42), -28)
|
||||||
|
self.assertEqual(self.S(), -42)
|
||||||
|
|
||||||
|
def test_void(self):
|
||||||
|
self._dll.tv_i.restype = None
|
||||||
|
self._dll.tv_i.argtypes = (c_int,)
|
||||||
|
self.assertEqual(self._dll.tv_i(42), None)
|
||||||
|
self.assertEqual(self.S(), 42)
|
||||||
|
self.assertEqual(self._dll.tv_i(-42), None)
|
||||||
|
self.assertEqual(self.S(), -42)
|
||||||
|
|
||||||
|
# The following repeats the above tests with stdcall functions (where
|
||||||
|
# they are available)
|
||||||
|
try:
|
||||||
|
WinDLL
|
||||||
|
except NameError:
|
||||||
|
def stdcall_dll(*_): pass
|
||||||
|
else:
|
||||||
|
class stdcall_dll(WinDLL):
|
||||||
|
def __getattr__(self, name):
|
||||||
|
if name[:2] == '__' and name[-2:] == '__':
|
||||||
|
raise AttributeError(name)
|
||||||
|
func = self._FuncPtr(("s_" + name, self))
|
||||||
|
setattr(self, name, func)
|
||||||
|
return func
|
||||||
|
|
||||||
|
@need_symbol('WinDLL')
|
||||||
|
class stdcallCFunctions(CFunctions):
|
||||||
|
_dll = stdcall_dll(_ctypes_test.__file__)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
36
Lib/ctypes/test/test_checkretval.py
vendored
Normal file
36
Lib/ctypes/test/test_checkretval.py
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
from ctypes import *
|
||||||
|
from ctypes.test import need_symbol
|
||||||
|
|
||||||
|
class CHECKED(c_int):
|
||||||
|
def _check_retval_(value):
|
||||||
|
# Receives a CHECKED instance.
|
||||||
|
return str(value.value)
|
||||||
|
_check_retval_ = staticmethod(_check_retval_)
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_checkretval(self):
|
||||||
|
|
||||||
|
import _ctypes_test
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
self.assertEqual(42, dll._testfunc_p_p(42))
|
||||||
|
|
||||||
|
dll._testfunc_p_p.restype = CHECKED
|
||||||
|
self.assertEqual("42", dll._testfunc_p_p(42))
|
||||||
|
|
||||||
|
dll._testfunc_p_p.restype = None
|
||||||
|
self.assertEqual(None, dll._testfunc_p_p(42))
|
||||||
|
|
||||||
|
del dll._testfunc_p_p.restype
|
||||||
|
self.assertEqual(42, dll._testfunc_p_p(42))
|
||||||
|
|
||||||
|
@need_symbol('oledll')
|
||||||
|
def test_oledll(self):
|
||||||
|
self.assertRaises(OSError,
|
||||||
|
oledll.oleaut32.CreateTypeLib2,
|
||||||
|
0, None, None)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
21
Lib/ctypes/test/test_delattr.py
vendored
Normal file
21
Lib/ctypes/test/test_delattr.py
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import unittest
|
||||||
|
from ctypes import *
|
||||||
|
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("foo", c_int)]
|
||||||
|
|
||||||
|
class TestCase(unittest.TestCase):
|
||||||
|
def test_simple(self):
|
||||||
|
self.assertRaises(TypeError,
|
||||||
|
delattr, c_int(42), "value")
|
||||||
|
|
||||||
|
def test_chararray(self):
|
||||||
|
self.assertRaises(TypeError,
|
||||||
|
delattr, (c_char * 5)(), "value")
|
||||||
|
|
||||||
|
def test_struct(self):
|
||||||
|
self.assertRaises(TypeError,
|
||||||
|
delattr, X(), "foo")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
76
Lib/ctypes/test/test_errno.py
vendored
Normal file
76
Lib/ctypes/test/test_errno.py
vendored
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import unittest, os, errno
|
||||||
|
import threading
|
||||||
|
|
||||||
|
from ctypes import *
|
||||||
|
from ctypes.util import find_library
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
def test_open(self):
|
||||||
|
libc_name = find_library("c")
|
||||||
|
if libc_name is None:
|
||||||
|
raise unittest.SkipTest("Unable to find C library")
|
||||||
|
libc = CDLL(libc_name, use_errno=True)
|
||||||
|
if os.name == "nt":
|
||||||
|
libc_open = libc._open
|
||||||
|
else:
|
||||||
|
libc_open = libc.open
|
||||||
|
|
||||||
|
libc_open.argtypes = c_char_p, c_int
|
||||||
|
|
||||||
|
self.assertEqual(libc_open(b"", 0), -1)
|
||||||
|
self.assertEqual(get_errno(), errno.ENOENT)
|
||||||
|
|
||||||
|
self.assertEqual(set_errno(32), errno.ENOENT)
|
||||||
|
self.assertEqual(get_errno(), 32)
|
||||||
|
|
||||||
|
def _worker():
|
||||||
|
set_errno(0)
|
||||||
|
|
||||||
|
libc = CDLL(libc_name, use_errno=False)
|
||||||
|
if os.name == "nt":
|
||||||
|
libc_open = libc._open
|
||||||
|
else:
|
||||||
|
libc_open = libc.open
|
||||||
|
libc_open.argtypes = c_char_p, c_int
|
||||||
|
self.assertEqual(libc_open(b"", 0), -1)
|
||||||
|
self.assertEqual(get_errno(), 0)
|
||||||
|
|
||||||
|
t = threading.Thread(target=_worker)
|
||||||
|
t.start()
|
||||||
|
t.join()
|
||||||
|
|
||||||
|
self.assertEqual(get_errno(), 32)
|
||||||
|
set_errno(0)
|
||||||
|
|
||||||
|
@unittest.skipUnless(os.name == "nt", 'Test specific to Windows')
|
||||||
|
def test_GetLastError(self):
|
||||||
|
dll = WinDLL("kernel32", use_last_error=True)
|
||||||
|
GetModuleHandle = dll.GetModuleHandleA
|
||||||
|
GetModuleHandle.argtypes = [c_wchar_p]
|
||||||
|
|
||||||
|
self.assertEqual(0, GetModuleHandle("foo"))
|
||||||
|
self.assertEqual(get_last_error(), 126)
|
||||||
|
|
||||||
|
self.assertEqual(set_last_error(32), 126)
|
||||||
|
self.assertEqual(get_last_error(), 32)
|
||||||
|
|
||||||
|
def _worker():
|
||||||
|
set_last_error(0)
|
||||||
|
|
||||||
|
dll = WinDLL("kernel32", use_last_error=False)
|
||||||
|
GetModuleHandle = dll.GetModuleHandleW
|
||||||
|
GetModuleHandle.argtypes = [c_wchar_p]
|
||||||
|
GetModuleHandle("bar")
|
||||||
|
|
||||||
|
self.assertEqual(get_last_error(), 0)
|
||||||
|
|
||||||
|
t = threading.Thread(target=_worker)
|
||||||
|
t.start()
|
||||||
|
t.join()
|
||||||
|
|
||||||
|
self.assertEqual(get_last_error(), 32)
|
||||||
|
|
||||||
|
set_last_error(0)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
127
Lib/ctypes/test/test_find.py
vendored
Normal file
127
Lib/ctypes/test/test_find.py
vendored
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
import unittest
|
||||||
|
import unittest.mock
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
import test.support
|
||||||
|
from test.support import os_helper
|
||||||
|
from ctypes import *
|
||||||
|
from ctypes.util import find_library
|
||||||
|
|
||||||
|
# On some systems, loading the OpenGL libraries needs the RTLD_GLOBAL mode.
|
||||||
|
class Test_OpenGL_libs(unittest.TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
lib_gl = lib_glu = lib_gle = None
|
||||||
|
if sys.platform == "win32":
|
||||||
|
lib_gl = find_library("OpenGL32")
|
||||||
|
lib_glu = find_library("Glu32")
|
||||||
|
elif sys.platform == "darwin":
|
||||||
|
lib_gl = lib_glu = find_library("OpenGL")
|
||||||
|
else:
|
||||||
|
lib_gl = find_library("GL")
|
||||||
|
lib_glu = find_library("GLU")
|
||||||
|
lib_gle = find_library("gle")
|
||||||
|
|
||||||
|
## print, for debugging
|
||||||
|
if test.support.verbose:
|
||||||
|
print("OpenGL libraries:")
|
||||||
|
for item in (("GL", lib_gl),
|
||||||
|
("GLU", lib_glu),
|
||||||
|
("gle", lib_gle)):
|
||||||
|
print("\t", item)
|
||||||
|
|
||||||
|
cls.gl = cls.glu = cls.gle = None
|
||||||
|
if lib_gl:
|
||||||
|
try:
|
||||||
|
cls.gl = CDLL(lib_gl, mode=RTLD_GLOBAL)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
if lib_glu:
|
||||||
|
try:
|
||||||
|
cls.glu = CDLL(lib_glu, RTLD_GLOBAL)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
if lib_gle:
|
||||||
|
try:
|
||||||
|
cls.gle = CDLL(lib_gle)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
cls.gl = cls.glu = cls.gle = None
|
||||||
|
|
||||||
|
def test_gl(self):
|
||||||
|
if self.gl is None:
|
||||||
|
self.skipTest('lib_gl not available')
|
||||||
|
self.gl.glClearIndex
|
||||||
|
|
||||||
|
def test_glu(self):
|
||||||
|
if self.glu is None:
|
||||||
|
self.skipTest('lib_glu not available')
|
||||||
|
self.glu.gluBeginCurve
|
||||||
|
|
||||||
|
def test_gle(self):
|
||||||
|
if self.gle is None:
|
||||||
|
self.skipTest('lib_gle not available')
|
||||||
|
self.gle.gleGetJoinStyle
|
||||||
|
|
||||||
|
def test_shell_injection(self):
|
||||||
|
result = find_library('; echo Hello shell > ' + os_helper.TESTFN)
|
||||||
|
self.assertFalse(os.path.lexists(os_helper.TESTFN))
|
||||||
|
self.assertIsNone(result)
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipUnless(sys.platform.startswith('linux'),
|
||||||
|
'Test only valid for Linux')
|
||||||
|
class FindLibraryLinux(unittest.TestCase):
|
||||||
|
def test_find_on_libpath(self):
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
try:
|
||||||
|
p = subprocess.Popen(['gcc', '--version'], stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.DEVNULL)
|
||||||
|
out, _ = p.communicate()
|
||||||
|
except OSError:
|
||||||
|
raise unittest.SkipTest('gcc, needed for test, not available')
|
||||||
|
with tempfile.TemporaryDirectory() as d:
|
||||||
|
# create an empty temporary file
|
||||||
|
srcname = os.path.join(d, 'dummy.c')
|
||||||
|
libname = 'py_ctypes_test_dummy'
|
||||||
|
dstname = os.path.join(d, 'lib%s.so' % libname)
|
||||||
|
with open(srcname, 'wb') as f:
|
||||||
|
pass
|
||||||
|
self.assertTrue(os.path.exists(srcname))
|
||||||
|
# compile the file to a shared library
|
||||||
|
cmd = ['gcc', '-o', dstname, '--shared',
|
||||||
|
'-Wl,-soname,lib%s.so' % libname, srcname]
|
||||||
|
out = subprocess.check_output(cmd)
|
||||||
|
self.assertTrue(os.path.exists(dstname))
|
||||||
|
# now check that the .so can't be found (since not in
|
||||||
|
# LD_LIBRARY_PATH)
|
||||||
|
self.assertIsNone(find_library(libname))
|
||||||
|
# now add the location to LD_LIBRARY_PATH
|
||||||
|
with os_helper.EnvironmentVarGuard() as env:
|
||||||
|
KEY = 'LD_LIBRARY_PATH'
|
||||||
|
if KEY not in env:
|
||||||
|
v = d
|
||||||
|
else:
|
||||||
|
v = '%s:%s' % (env[KEY], d)
|
||||||
|
env.set(KEY, v)
|
||||||
|
# now check that the .so can be found (since in
|
||||||
|
# LD_LIBRARY_PATH)
|
||||||
|
self.assertEqual(find_library(libname), 'lib%s.so' % libname)
|
||||||
|
|
||||||
|
def test_find_library_with_gcc(self):
|
||||||
|
with unittest.mock.patch("ctypes.util._findSoname_ldconfig", lambda *args: None):
|
||||||
|
self.assertNotEqual(find_library('c'), None)
|
||||||
|
|
||||||
|
def test_find_library_with_ld(self):
|
||||||
|
with unittest.mock.patch("ctypes.util._findSoname_ldconfig", lambda *args: None), \
|
||||||
|
unittest.mock.patch("ctypes.util._findLib_gcc", lambda *args: None):
|
||||||
|
self.assertNotEqual(find_library('c'), None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
141
Lib/ctypes/test/test_frombuffer.py
vendored
Normal file
141
Lib/ctypes/test/test_frombuffer.py
vendored
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
from ctypes import *
|
||||||
|
import array
|
||||||
|
import gc
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("c_int", c_int)]
|
||||||
|
init_called = False
|
||||||
|
def __init__(self):
|
||||||
|
self._init_called = True
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
def test_from_buffer(self):
|
||||||
|
a = array.array("i", range(16))
|
||||||
|
x = (c_int * 16).from_buffer(a)
|
||||||
|
|
||||||
|
y = X.from_buffer(a)
|
||||||
|
self.assertEqual(y.c_int, a[0])
|
||||||
|
self.assertFalse(y.init_called)
|
||||||
|
|
||||||
|
self.assertEqual(x[:], a.tolist())
|
||||||
|
|
||||||
|
a[0], a[-1] = 200, -200
|
||||||
|
self.assertEqual(x[:], a.tolist())
|
||||||
|
|
||||||
|
self.assertRaises(BufferError, a.append, 100)
|
||||||
|
self.assertRaises(BufferError, a.pop)
|
||||||
|
|
||||||
|
del x; del y; gc.collect(); gc.collect(); gc.collect()
|
||||||
|
a.append(100)
|
||||||
|
a.pop()
|
||||||
|
x = (c_int * 16).from_buffer(a)
|
||||||
|
|
||||||
|
self.assertIn(a, [obj.obj if isinstance(obj, memoryview) else obj
|
||||||
|
for obj in x._objects.values()])
|
||||||
|
|
||||||
|
expected = x[:]
|
||||||
|
del a; gc.collect(); gc.collect(); gc.collect()
|
||||||
|
self.assertEqual(x[:], expected)
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(TypeError, "not writable"):
|
||||||
|
(c_char * 16).from_buffer(b"a" * 16)
|
||||||
|
with self.assertRaisesRegex(TypeError, "not writable"):
|
||||||
|
(c_char * 16).from_buffer(memoryview(b"a" * 16))
|
||||||
|
with self.assertRaisesRegex(TypeError, "not C contiguous"):
|
||||||
|
(c_char * 16).from_buffer(memoryview(bytearray(b"a" * 16))[::-1])
|
||||||
|
msg = "bytes-like object is required"
|
||||||
|
with self.assertRaisesRegex(TypeError, msg):
|
||||||
|
(c_char * 16).from_buffer("a" * 16)
|
||||||
|
|
||||||
|
def test_fortran_contiguous(self):
|
||||||
|
try:
|
||||||
|
import _testbuffer
|
||||||
|
except ImportError as err:
|
||||||
|
self.skipTest(str(err))
|
||||||
|
flags = _testbuffer.ND_WRITABLE | _testbuffer.ND_FORTRAN
|
||||||
|
array = _testbuffer.ndarray(
|
||||||
|
[97] * 16, format="B", shape=[4, 4], flags=flags)
|
||||||
|
with self.assertRaisesRegex(TypeError, "not C contiguous"):
|
||||||
|
(c_char * 16).from_buffer(array)
|
||||||
|
array = memoryview(array)
|
||||||
|
self.assertTrue(array.f_contiguous)
|
||||||
|
self.assertFalse(array.c_contiguous)
|
||||||
|
with self.assertRaisesRegex(TypeError, "not C contiguous"):
|
||||||
|
(c_char * 16).from_buffer(array)
|
||||||
|
|
||||||
|
def test_from_buffer_with_offset(self):
|
||||||
|
a = array.array("i", range(16))
|
||||||
|
x = (c_int * 15).from_buffer(a, sizeof(c_int))
|
||||||
|
|
||||||
|
self.assertEqual(x[:], a.tolist()[1:])
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
c_int.from_buffer(a, -1)
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
(c_int * 16).from_buffer(a, sizeof(c_int))
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
(c_int * 1).from_buffer(a, 16 * sizeof(c_int))
|
||||||
|
|
||||||
|
def test_from_buffer_memoryview(self):
|
||||||
|
a = [c_char.from_buffer(memoryview(bytearray(b'a')))]
|
||||||
|
a.append(a)
|
||||||
|
del a
|
||||||
|
gc.collect() # Should not crash
|
||||||
|
|
||||||
|
def test_from_buffer_copy(self):
|
||||||
|
a = array.array("i", range(16))
|
||||||
|
x = (c_int * 16).from_buffer_copy(a)
|
||||||
|
|
||||||
|
y = X.from_buffer_copy(a)
|
||||||
|
self.assertEqual(y.c_int, a[0])
|
||||||
|
self.assertFalse(y.init_called)
|
||||||
|
|
||||||
|
self.assertEqual(x[:], list(range(16)))
|
||||||
|
|
||||||
|
a[0], a[-1] = 200, -200
|
||||||
|
self.assertEqual(x[:], list(range(16)))
|
||||||
|
|
||||||
|
a.append(100)
|
||||||
|
self.assertEqual(x[:], list(range(16)))
|
||||||
|
|
||||||
|
self.assertEqual(x._objects, None)
|
||||||
|
|
||||||
|
del a; gc.collect(); gc.collect(); gc.collect()
|
||||||
|
self.assertEqual(x[:], list(range(16)))
|
||||||
|
|
||||||
|
x = (c_char * 16).from_buffer_copy(b"a" * 16)
|
||||||
|
self.assertEqual(x[:], b"a" * 16)
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
(c_char * 16).from_buffer_copy("a" * 16)
|
||||||
|
|
||||||
|
def test_from_buffer_copy_with_offset(self):
|
||||||
|
a = array.array("i", range(16))
|
||||||
|
x = (c_int * 15).from_buffer_copy(a, sizeof(c_int))
|
||||||
|
|
||||||
|
self.assertEqual(x[:], a.tolist()[1:])
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
c_int.from_buffer_copy(a, -1)
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
(c_int * 16).from_buffer_copy(a, sizeof(c_int))
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
(c_int * 1).from_buffer_copy(a, 16 * sizeof(c_int))
|
||||||
|
|
||||||
|
def test_abstract(self):
|
||||||
|
from ctypes import _Pointer, _SimpleCData, _CFuncPtr
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, Array.from_buffer, bytearray(10))
|
||||||
|
self.assertRaises(TypeError, Structure.from_buffer, bytearray(10))
|
||||||
|
self.assertRaises(TypeError, Union.from_buffer, bytearray(10))
|
||||||
|
self.assertRaises(TypeError, _CFuncPtr.from_buffer, bytearray(10))
|
||||||
|
self.assertRaises(TypeError, _Pointer.from_buffer, bytearray(10))
|
||||||
|
self.assertRaises(TypeError, _SimpleCData.from_buffer, bytearray(10))
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, Array.from_buffer_copy, b"123")
|
||||||
|
self.assertRaises(TypeError, Structure.from_buffer_copy, b"123")
|
||||||
|
self.assertRaises(TypeError, Union.from_buffer_copy, b"123")
|
||||||
|
self.assertRaises(TypeError, _CFuncPtr.from_buffer_copy, b"123")
|
||||||
|
self.assertRaises(TypeError, _Pointer.from_buffer_copy, b"123")
|
||||||
|
self.assertRaises(TypeError, _SimpleCData.from_buffer_copy, b"123")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
132
Lib/ctypes/test/test_funcptr.py
vendored
Normal file
132
Lib/ctypes/test/test_funcptr.py
vendored
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
import unittest
|
||||||
|
from ctypes import *
|
||||||
|
|
||||||
|
try:
|
||||||
|
WINFUNCTYPE
|
||||||
|
except NameError:
|
||||||
|
# fake to enable this test on Linux
|
||||||
|
WINFUNCTYPE = CFUNCTYPE
|
||||||
|
|
||||||
|
import _ctypes_test
|
||||||
|
lib = CDLL(_ctypes_test.__file__)
|
||||||
|
|
||||||
|
class CFuncPtrTestCase(unittest.TestCase):
|
||||||
|
def test_basic(self):
|
||||||
|
X = WINFUNCTYPE(c_int, c_int, c_int)
|
||||||
|
|
||||||
|
def func(*args):
|
||||||
|
return len(args)
|
||||||
|
|
||||||
|
x = X(func)
|
||||||
|
self.assertEqual(x.restype, c_int)
|
||||||
|
self.assertEqual(x.argtypes, (c_int, c_int))
|
||||||
|
self.assertEqual(sizeof(x), sizeof(c_voidp))
|
||||||
|
self.assertEqual(sizeof(X), sizeof(c_voidp))
|
||||||
|
|
||||||
|
def test_first(self):
|
||||||
|
StdCallback = WINFUNCTYPE(c_int, c_int, c_int)
|
||||||
|
CdeclCallback = CFUNCTYPE(c_int, c_int, c_int)
|
||||||
|
|
||||||
|
def func(a, b):
|
||||||
|
return a + b
|
||||||
|
|
||||||
|
s = StdCallback(func)
|
||||||
|
c = CdeclCallback(func)
|
||||||
|
|
||||||
|
self.assertEqual(s(1, 2), 3)
|
||||||
|
self.assertEqual(c(1, 2), 3)
|
||||||
|
# The following no longer raises a TypeError - it is now
|
||||||
|
# possible, as in C, to call cdecl functions with more parameters.
|
||||||
|
#self.assertRaises(TypeError, c, 1, 2, 3)
|
||||||
|
self.assertEqual(c(1, 2, 3, 4, 5, 6), 3)
|
||||||
|
if not WINFUNCTYPE is CFUNCTYPE:
|
||||||
|
self.assertRaises(TypeError, s, 1, 2, 3)
|
||||||
|
|
||||||
|
def test_structures(self):
|
||||||
|
WNDPROC = WINFUNCTYPE(c_long, c_int, c_int, c_int, c_int)
|
||||||
|
|
||||||
|
def wndproc(hwnd, msg, wParam, lParam):
|
||||||
|
return hwnd + msg + wParam + lParam
|
||||||
|
|
||||||
|
HINSTANCE = c_int
|
||||||
|
HICON = c_int
|
||||||
|
HCURSOR = c_int
|
||||||
|
LPCTSTR = c_char_p
|
||||||
|
|
||||||
|
class WNDCLASS(Structure):
|
||||||
|
_fields_ = [("style", c_uint),
|
||||||
|
("lpfnWndProc", WNDPROC),
|
||||||
|
("cbClsExtra", c_int),
|
||||||
|
("cbWndExtra", c_int),
|
||||||
|
("hInstance", HINSTANCE),
|
||||||
|
("hIcon", HICON),
|
||||||
|
("hCursor", HCURSOR),
|
||||||
|
("lpszMenuName", LPCTSTR),
|
||||||
|
("lpszClassName", LPCTSTR)]
|
||||||
|
|
||||||
|
wndclass = WNDCLASS()
|
||||||
|
wndclass.lpfnWndProc = WNDPROC(wndproc)
|
||||||
|
|
||||||
|
WNDPROC_2 = WINFUNCTYPE(c_long, c_int, c_int, c_int, c_int)
|
||||||
|
|
||||||
|
# This is no longer true, now that WINFUNCTYPE caches created types internally.
|
||||||
|
## # CFuncPtr subclasses are compared by identity, so this raises a TypeError:
|
||||||
|
## self.assertRaises(TypeError, setattr, wndclass,
|
||||||
|
## "lpfnWndProc", WNDPROC_2(wndproc))
|
||||||
|
# instead:
|
||||||
|
|
||||||
|
self.assertIs(WNDPROC, WNDPROC_2)
|
||||||
|
# 'wndclass.lpfnWndProc' leaks 94 references. Why?
|
||||||
|
self.assertEqual(wndclass.lpfnWndProc(1, 2, 3, 4), 10)
|
||||||
|
|
||||||
|
|
||||||
|
f = wndclass.lpfnWndProc
|
||||||
|
|
||||||
|
del wndclass
|
||||||
|
del wndproc
|
||||||
|
|
||||||
|
self.assertEqual(f(10, 11, 12, 13), 46)
|
||||||
|
|
||||||
|
def test_dllfunctions(self):
|
||||||
|
|
||||||
|
def NoNullHandle(value):
|
||||||
|
if not value:
|
||||||
|
raise WinError()
|
||||||
|
return value
|
||||||
|
|
||||||
|
strchr = lib.my_strchr
|
||||||
|
strchr.restype = c_char_p
|
||||||
|
strchr.argtypes = (c_char_p, c_char)
|
||||||
|
self.assertEqual(strchr(b"abcdefghi", b"b"), b"bcdefghi")
|
||||||
|
self.assertEqual(strchr(b"abcdefghi", b"x"), None)
|
||||||
|
|
||||||
|
|
||||||
|
strtok = lib.my_strtok
|
||||||
|
strtok.restype = c_char_p
|
||||||
|
# Neither of this does work: strtok changes the buffer it is passed
|
||||||
|
## strtok.argtypes = (c_char_p, c_char_p)
|
||||||
|
## strtok.argtypes = (c_string, c_char_p)
|
||||||
|
|
||||||
|
def c_string(init):
|
||||||
|
size = len(init) + 1
|
||||||
|
return (c_char*size)(*init)
|
||||||
|
|
||||||
|
s = b"a\nb\nc"
|
||||||
|
b = c_string(s)
|
||||||
|
|
||||||
|
## b = (c_char * (len(s)+1))()
|
||||||
|
## b.value = s
|
||||||
|
|
||||||
|
## b = c_string(s)
|
||||||
|
self.assertEqual(strtok(b, b"\n"), b"a")
|
||||||
|
self.assertEqual(strtok(None, b"\n"), b"b")
|
||||||
|
self.assertEqual(strtok(None, b"\n"), b"c")
|
||||||
|
self.assertEqual(strtok(None, b"\n"), None)
|
||||||
|
|
||||||
|
def test_abstract(self):
|
||||||
|
from ctypes import _CFuncPtr
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, _CFuncPtr, 13, "name", 42, "iid")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
384
Lib/ctypes/test/test_functions.py
vendored
Normal file
384
Lib/ctypes/test/test_functions.py
vendored
Normal file
@@ -0,0 +1,384 @@
|
|||||||
|
"""
|
||||||
|
Here is probably the place to write the docs, since the test-cases
|
||||||
|
show how the type behave.
|
||||||
|
|
||||||
|
Later...
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ctypes import *
|
||||||
|
from ctypes.test import need_symbol
|
||||||
|
import sys, unittest
|
||||||
|
|
||||||
|
try:
|
||||||
|
WINFUNCTYPE
|
||||||
|
except NameError:
|
||||||
|
# fake to enable this test on Linux
|
||||||
|
WINFUNCTYPE = CFUNCTYPE
|
||||||
|
|
||||||
|
import _ctypes_test
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
if sys.platform == "win32":
|
||||||
|
windll = WinDLL(_ctypes_test.__file__)
|
||||||
|
|
||||||
|
class POINT(Structure):
|
||||||
|
_fields_ = [("x", c_int), ("y", c_int)]
|
||||||
|
class RECT(Structure):
|
||||||
|
_fields_ = [("left", c_int), ("top", c_int),
|
||||||
|
("right", c_int), ("bottom", c_int)]
|
||||||
|
class FunctionTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_mro(self):
|
||||||
|
# in Python 2.3, this raises TypeError: MRO conflict among bases classes,
|
||||||
|
# in Python 2.2 it works.
|
||||||
|
#
|
||||||
|
# But in early versions of _ctypes.c, the result of tp_new
|
||||||
|
# wasn't checked, and it even crashed Python.
|
||||||
|
# Found by Greg Chapman.
|
||||||
|
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
class X(object, Array):
|
||||||
|
_length_ = 5
|
||||||
|
_type_ = "i"
|
||||||
|
|
||||||
|
from _ctypes import _Pointer
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
class X(object, _Pointer):
|
||||||
|
pass
|
||||||
|
|
||||||
|
from _ctypes import _SimpleCData
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
class X(object, _SimpleCData):
|
||||||
|
_type_ = "i"
|
||||||
|
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
class X(object, Structure):
|
||||||
|
_fields_ = []
|
||||||
|
|
||||||
|
@need_symbol('c_wchar')
|
||||||
|
def test_wchar_parm(self):
|
||||||
|
f = dll._testfunc_i_bhilfd
|
||||||
|
f.argtypes = [c_byte, c_wchar, c_int, c_long, c_float, c_double]
|
||||||
|
result = f(1, "x", 3, 4, 5.0, 6.0)
|
||||||
|
self.assertEqual(result, 139)
|
||||||
|
self.assertEqual(type(result), int)
|
||||||
|
|
||||||
|
@need_symbol('c_wchar')
|
||||||
|
def test_wchar_result(self):
|
||||||
|
f = dll._testfunc_i_bhilfd
|
||||||
|
f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
|
||||||
|
f.restype = c_wchar
|
||||||
|
result = f(0, 0, 0, 0, 0, 0)
|
||||||
|
self.assertEqual(result, '\x00')
|
||||||
|
|
||||||
|
def test_voidresult(self):
|
||||||
|
f = dll._testfunc_v
|
||||||
|
f.restype = None
|
||||||
|
f.argtypes = [c_int, c_int, POINTER(c_int)]
|
||||||
|
result = c_int()
|
||||||
|
self.assertEqual(None, f(1, 2, byref(result)))
|
||||||
|
self.assertEqual(result.value, 3)
|
||||||
|
|
||||||
|
def test_intresult(self):
|
||||||
|
f = dll._testfunc_i_bhilfd
|
||||||
|
f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
|
||||||
|
f.restype = c_int
|
||||||
|
result = f(1, 2, 3, 4, 5.0, 6.0)
|
||||||
|
self.assertEqual(result, 21)
|
||||||
|
self.assertEqual(type(result), int)
|
||||||
|
|
||||||
|
result = f(-1, -2, -3, -4, -5.0, -6.0)
|
||||||
|
self.assertEqual(result, -21)
|
||||||
|
self.assertEqual(type(result), int)
|
||||||
|
|
||||||
|
# If we declare the function to return a short,
|
||||||
|
# is the high part split off?
|
||||||
|
f.restype = c_short
|
||||||
|
result = f(1, 2, 3, 4, 5.0, 6.0)
|
||||||
|
self.assertEqual(result, 21)
|
||||||
|
self.assertEqual(type(result), int)
|
||||||
|
|
||||||
|
result = f(1, 2, 3, 0x10004, 5.0, 6.0)
|
||||||
|
self.assertEqual(result, 21)
|
||||||
|
self.assertEqual(type(result), int)
|
||||||
|
|
||||||
|
# You cannot assign character format codes as restype any longer
|
||||||
|
self.assertRaises(TypeError, setattr, f, "restype", "i")
|
||||||
|
|
||||||
|
def test_floatresult(self):
|
||||||
|
f = dll._testfunc_f_bhilfd
|
||||||
|
f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
|
||||||
|
f.restype = c_float
|
||||||
|
result = f(1, 2, 3, 4, 5.0, 6.0)
|
||||||
|
self.assertEqual(result, 21)
|
||||||
|
self.assertEqual(type(result), float)
|
||||||
|
|
||||||
|
result = f(-1, -2, -3, -4, -5.0, -6.0)
|
||||||
|
self.assertEqual(result, -21)
|
||||||
|
self.assertEqual(type(result), float)
|
||||||
|
|
||||||
|
def test_doubleresult(self):
|
||||||
|
f = dll._testfunc_d_bhilfd
|
||||||
|
f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
|
||||||
|
f.restype = c_double
|
||||||
|
result = f(1, 2, 3, 4, 5.0, 6.0)
|
||||||
|
self.assertEqual(result, 21)
|
||||||
|
self.assertEqual(type(result), float)
|
||||||
|
|
||||||
|
result = f(-1, -2, -3, -4, -5.0, -6.0)
|
||||||
|
self.assertEqual(result, -21)
|
||||||
|
self.assertEqual(type(result), float)
|
||||||
|
|
||||||
|
@need_symbol('c_longdouble')
|
||||||
|
def test_longdoubleresult(self):
|
||||||
|
f = dll._testfunc_D_bhilfD
|
||||||
|
f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_longdouble]
|
||||||
|
f.restype = c_longdouble
|
||||||
|
result = f(1, 2, 3, 4, 5.0, 6.0)
|
||||||
|
self.assertEqual(result, 21)
|
||||||
|
self.assertEqual(type(result), float)
|
||||||
|
|
||||||
|
result = f(-1, -2, -3, -4, -5.0, -6.0)
|
||||||
|
self.assertEqual(result, -21)
|
||||||
|
self.assertEqual(type(result), float)
|
||||||
|
|
||||||
|
@need_symbol('c_longlong')
|
||||||
|
def test_longlongresult(self):
|
||||||
|
f = dll._testfunc_q_bhilfd
|
||||||
|
f.restype = c_longlong
|
||||||
|
f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
|
||||||
|
result = f(1, 2, 3, 4, 5.0, 6.0)
|
||||||
|
self.assertEqual(result, 21)
|
||||||
|
|
||||||
|
f = dll._testfunc_q_bhilfdq
|
||||||
|
f.restype = c_longlong
|
||||||
|
f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double, c_longlong]
|
||||||
|
result = f(1, 2, 3, 4, 5.0, 6.0, 21)
|
||||||
|
self.assertEqual(result, 42)
|
||||||
|
|
||||||
|
def test_stringresult(self):
|
||||||
|
f = dll._testfunc_p_p
|
||||||
|
f.argtypes = None
|
||||||
|
f.restype = c_char_p
|
||||||
|
result = f(b"123")
|
||||||
|
self.assertEqual(result, b"123")
|
||||||
|
|
||||||
|
result = f(None)
|
||||||
|
self.assertEqual(result, None)
|
||||||
|
|
||||||
|
def test_pointers(self):
|
||||||
|
f = dll._testfunc_p_p
|
||||||
|
f.restype = POINTER(c_int)
|
||||||
|
f.argtypes = [POINTER(c_int)]
|
||||||
|
|
||||||
|
# This only works if the value c_int(42) passed to the
|
||||||
|
# function is still alive while the pointer (the result) is
|
||||||
|
# used.
|
||||||
|
|
||||||
|
v = c_int(42)
|
||||||
|
|
||||||
|
self.assertEqual(pointer(v).contents.value, 42)
|
||||||
|
result = f(pointer(v))
|
||||||
|
self.assertEqual(type(result), POINTER(c_int))
|
||||||
|
self.assertEqual(result.contents.value, 42)
|
||||||
|
|
||||||
|
# This on works...
|
||||||
|
result = f(pointer(v))
|
||||||
|
self.assertEqual(result.contents.value, v.value)
|
||||||
|
|
||||||
|
p = pointer(c_int(99))
|
||||||
|
result = f(p)
|
||||||
|
self.assertEqual(result.contents.value, 99)
|
||||||
|
|
||||||
|
arg = byref(v)
|
||||||
|
result = f(arg)
|
||||||
|
self.assertNotEqual(result.contents, v.value)
|
||||||
|
|
||||||
|
self.assertRaises(ArgumentError, f, byref(c_short(22)))
|
||||||
|
|
||||||
|
# It is dangerous, however, because you don't control the lifetime
|
||||||
|
# of the pointer:
|
||||||
|
result = f(byref(c_int(99)))
|
||||||
|
self.assertNotEqual(result.contents, 99)
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
def test_shorts(self):
|
||||||
|
f = dll._testfunc_callback_i_if
|
||||||
|
|
||||||
|
args = []
|
||||||
|
expected = [262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048,
|
||||||
|
1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1]
|
||||||
|
|
||||||
|
def callback(v):
|
||||||
|
args.append(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
CallBack = CFUNCTYPE(c_int, c_int)
|
||||||
|
|
||||||
|
cb = CallBack(callback)
|
||||||
|
f(2**18, cb)
|
||||||
|
self.assertEqual(args, expected)
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
|
||||||
|
def test_callbacks(self):
|
||||||
|
f = dll._testfunc_callback_i_if
|
||||||
|
f.restype = c_int
|
||||||
|
f.argtypes = None
|
||||||
|
|
||||||
|
MyCallback = CFUNCTYPE(c_int, c_int)
|
||||||
|
|
||||||
|
def callback(value):
|
||||||
|
#print "called back with", value
|
||||||
|
return value
|
||||||
|
|
||||||
|
cb = MyCallback(callback)
|
||||||
|
result = f(-10, cb)
|
||||||
|
self.assertEqual(result, -18)
|
||||||
|
|
||||||
|
# test with prototype
|
||||||
|
f.argtypes = [c_int, MyCallback]
|
||||||
|
cb = MyCallback(callback)
|
||||||
|
result = f(-10, cb)
|
||||||
|
self.assertEqual(result, -18)
|
||||||
|
|
||||||
|
AnotherCallback = WINFUNCTYPE(c_int, c_int, c_int, c_int, c_int)
|
||||||
|
|
||||||
|
# check that the prototype works: we call f with wrong
|
||||||
|
# argument types
|
||||||
|
cb = AnotherCallback(callback)
|
||||||
|
self.assertRaises(ArgumentError, f, -10, cb)
|
||||||
|
|
||||||
|
|
||||||
|
def test_callbacks_2(self):
|
||||||
|
# Can also use simple datatypes as argument type specifiers
|
||||||
|
# for the callback function.
|
||||||
|
# In this case the call receives an instance of that type
|
||||||
|
f = dll._testfunc_callback_i_if
|
||||||
|
f.restype = c_int
|
||||||
|
|
||||||
|
MyCallback = CFUNCTYPE(c_int, c_int)
|
||||||
|
|
||||||
|
f.argtypes = [c_int, MyCallback]
|
||||||
|
|
||||||
|
def callback(value):
|
||||||
|
#print "called back with", value
|
||||||
|
self.assertEqual(type(value), int)
|
||||||
|
return value
|
||||||
|
|
||||||
|
cb = MyCallback(callback)
|
||||||
|
result = f(-10, cb)
|
||||||
|
self.assertEqual(result, -18)
|
||||||
|
|
||||||
|
@need_symbol('c_longlong')
|
||||||
|
def test_longlong_callbacks(self):
|
||||||
|
|
||||||
|
f = dll._testfunc_callback_q_qf
|
||||||
|
f.restype = c_longlong
|
||||||
|
|
||||||
|
MyCallback = CFUNCTYPE(c_longlong, c_longlong)
|
||||||
|
|
||||||
|
f.argtypes = [c_longlong, MyCallback]
|
||||||
|
|
||||||
|
def callback(value):
|
||||||
|
self.assertIsInstance(value, int)
|
||||||
|
return value & 0x7FFFFFFF
|
||||||
|
|
||||||
|
cb = MyCallback(callback)
|
||||||
|
|
||||||
|
self.assertEqual(13577625587, f(1000000000000, cb))
|
||||||
|
|
||||||
|
def test_errors(self):
|
||||||
|
self.assertRaises(AttributeError, getattr, dll, "_xxx_yyy")
|
||||||
|
self.assertRaises(ValueError, c_int.in_dll, dll, "_xxx_yyy")
|
||||||
|
|
||||||
|
def test_byval(self):
|
||||||
|
|
||||||
|
# without prototype
|
||||||
|
ptin = POINT(1, 2)
|
||||||
|
ptout = POINT()
|
||||||
|
# EXPORT int _testfunc_byval(point in, point *pout)
|
||||||
|
result = dll._testfunc_byval(ptin, byref(ptout))
|
||||||
|
got = result, ptout.x, ptout.y
|
||||||
|
expected = 3, 1, 2
|
||||||
|
self.assertEqual(got, expected)
|
||||||
|
|
||||||
|
# with prototype
|
||||||
|
ptin = POINT(101, 102)
|
||||||
|
ptout = POINT()
|
||||||
|
dll._testfunc_byval.argtypes = (POINT, POINTER(POINT))
|
||||||
|
dll._testfunc_byval.restype = c_int
|
||||||
|
result = dll._testfunc_byval(ptin, byref(ptout))
|
||||||
|
got = result, ptout.x, ptout.y
|
||||||
|
expected = 203, 101, 102
|
||||||
|
self.assertEqual(got, expected)
|
||||||
|
|
||||||
|
def test_struct_return_2H(self):
|
||||||
|
class S2H(Structure):
|
||||||
|
_fields_ = [("x", c_short),
|
||||||
|
("y", c_short)]
|
||||||
|
dll.ret_2h_func.restype = S2H
|
||||||
|
dll.ret_2h_func.argtypes = [S2H]
|
||||||
|
inp = S2H(99, 88)
|
||||||
|
s2h = dll.ret_2h_func(inp)
|
||||||
|
self.assertEqual((s2h.x, s2h.y), (99*2, 88*3))
|
||||||
|
|
||||||
|
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
|
||||||
|
def test_struct_return_2H_stdcall(self):
|
||||||
|
class S2H(Structure):
|
||||||
|
_fields_ = [("x", c_short),
|
||||||
|
("y", c_short)]
|
||||||
|
|
||||||
|
windll.s_ret_2h_func.restype = S2H
|
||||||
|
windll.s_ret_2h_func.argtypes = [S2H]
|
||||||
|
s2h = windll.s_ret_2h_func(S2H(99, 88))
|
||||||
|
self.assertEqual((s2h.x, s2h.y), (99*2, 88*3))
|
||||||
|
|
||||||
|
def test_struct_return_8H(self):
|
||||||
|
class S8I(Structure):
|
||||||
|
_fields_ = [("a", c_int),
|
||||||
|
("b", c_int),
|
||||||
|
("c", c_int),
|
||||||
|
("d", c_int),
|
||||||
|
("e", c_int),
|
||||||
|
("f", c_int),
|
||||||
|
("g", c_int),
|
||||||
|
("h", c_int)]
|
||||||
|
dll.ret_8i_func.restype = S8I
|
||||||
|
dll.ret_8i_func.argtypes = [S8I]
|
||||||
|
inp = S8I(9, 8, 7, 6, 5, 4, 3, 2)
|
||||||
|
s8i = dll.ret_8i_func(inp)
|
||||||
|
self.assertEqual((s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h),
|
||||||
|
(9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9))
|
||||||
|
|
||||||
|
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
|
||||||
|
def test_struct_return_8H_stdcall(self):
|
||||||
|
class S8I(Structure):
|
||||||
|
_fields_ = [("a", c_int),
|
||||||
|
("b", c_int),
|
||||||
|
("c", c_int),
|
||||||
|
("d", c_int),
|
||||||
|
("e", c_int),
|
||||||
|
("f", c_int),
|
||||||
|
("g", c_int),
|
||||||
|
("h", c_int)]
|
||||||
|
windll.s_ret_8i_func.restype = S8I
|
||||||
|
windll.s_ret_8i_func.argtypes = [S8I]
|
||||||
|
inp = S8I(9, 8, 7, 6, 5, 4, 3, 2)
|
||||||
|
s8i = windll.s_ret_8i_func(inp)
|
||||||
|
self.assertEqual(
|
||||||
|
(s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h),
|
||||||
|
(9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9))
|
||||||
|
|
||||||
|
def test_sf1651235(self):
|
||||||
|
# see https://www.python.org/sf/1651235
|
||||||
|
|
||||||
|
proto = CFUNCTYPE(c_int, RECT, POINT)
|
||||||
|
def callback(*args):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
callback = proto(callback)
|
||||||
|
self.assertRaises(ArgumentError, lambda: callback((1, 2, 3, 4), POINT()))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
42
Lib/ctypes/test/test_incomplete.py
vendored
Normal file
42
Lib/ctypes/test/test_incomplete.py
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import unittest
|
||||||
|
from ctypes import *
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
#
|
||||||
|
# The incomplete pointer example from the tutorial
|
||||||
|
#
|
||||||
|
|
||||||
|
class MyTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_incomplete_example(self):
|
||||||
|
lpcell = POINTER("cell")
|
||||||
|
class cell(Structure):
|
||||||
|
_fields_ = [("name", c_char_p),
|
||||||
|
("next", lpcell)]
|
||||||
|
|
||||||
|
SetPointerType(lpcell, cell)
|
||||||
|
|
||||||
|
c1 = cell()
|
||||||
|
c1.name = b"foo"
|
||||||
|
c2 = cell()
|
||||||
|
c2.name = b"bar"
|
||||||
|
|
||||||
|
c1.next = pointer(c2)
|
||||||
|
c2.next = pointer(c1)
|
||||||
|
|
||||||
|
p = c1
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for i in range(8):
|
||||||
|
result.append(p.name)
|
||||||
|
p = p.next[0]
|
||||||
|
self.assertEqual(result, [b"foo", b"bar"] * 4)
|
||||||
|
|
||||||
|
# to not leak references, we must clean _pointer_type_cache
|
||||||
|
from ctypes import _pointer_type_cache
|
||||||
|
del _pointer_type_cache[cell]
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
40
Lib/ctypes/test/test_init.py
vendored
Normal file
40
Lib/ctypes/test/test_init.py
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
from ctypes import *
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_int),
|
||||||
|
("b", c_int)]
|
||||||
|
new_was_called = False
|
||||||
|
|
||||||
|
def __new__(cls):
|
||||||
|
result = super().__new__(cls)
|
||||||
|
result.new_was_called = True
|
||||||
|
return result
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.a = 9
|
||||||
|
self.b = 12
|
||||||
|
|
||||||
|
class Y(Structure):
|
||||||
|
_fields_ = [("x", X)]
|
||||||
|
|
||||||
|
|
||||||
|
class InitTest(unittest.TestCase):
|
||||||
|
def test_get(self):
|
||||||
|
# make sure the only accessing a nested structure
|
||||||
|
# doesn't call the structure's __new__ and __init__
|
||||||
|
y = Y()
|
||||||
|
self.assertEqual((y.x.a, y.x.b), (0, 0))
|
||||||
|
self.assertEqual(y.x.new_was_called, False)
|
||||||
|
|
||||||
|
# But explicitly creating an X structure calls __new__ and __init__, of course.
|
||||||
|
x = X()
|
||||||
|
self.assertEqual((x.a, x.b), (9, 12))
|
||||||
|
self.assertEqual(x.new_was_called, True)
|
||||||
|
|
||||||
|
y.x = x
|
||||||
|
self.assertEqual((y.x.a, y.x.b), (9, 12))
|
||||||
|
self.assertEqual(y.x.new_was_called, False)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
100
Lib/ctypes/test/test_internals.py
vendored
Normal file
100
Lib/ctypes/test/test_internals.py
vendored
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
# This tests the internal _objects attribute
|
||||||
|
import unittest
|
||||||
|
from ctypes import *
|
||||||
|
from sys import getrefcount as grc
|
||||||
|
|
||||||
|
# XXX This test must be reviewed for correctness!!!
|
||||||
|
|
||||||
|
# ctypes' types are container types.
|
||||||
|
#
|
||||||
|
# They have an internal memory block, which only consists of some bytes,
|
||||||
|
# but it has to keep references to other objects as well. This is not
|
||||||
|
# really needed for trivial C types like int or char, but it is important
|
||||||
|
# for aggregate types like strings or pointers in particular.
|
||||||
|
#
|
||||||
|
# What about pointers?
|
||||||
|
|
||||||
|
class ObjectsTestCase(unittest.TestCase):
|
||||||
|
def assertSame(self, a, b):
|
||||||
|
self.assertEqual(id(a), id(b))
|
||||||
|
|
||||||
|
def test_ints(self):
|
||||||
|
i = 42000123
|
||||||
|
refcnt = grc(i)
|
||||||
|
ci = c_int(i)
|
||||||
|
self.assertEqual(refcnt, grc(i))
|
||||||
|
self.assertEqual(ci._objects, None)
|
||||||
|
|
||||||
|
def test_c_char_p(self):
|
||||||
|
s = b"Hello, World"
|
||||||
|
refcnt = grc(s)
|
||||||
|
cs = c_char_p(s)
|
||||||
|
self.assertEqual(refcnt + 1, grc(s))
|
||||||
|
self.assertSame(cs._objects, s)
|
||||||
|
|
||||||
|
def test_simple_struct(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_int), ("b", c_int)]
|
||||||
|
|
||||||
|
a = 421234
|
||||||
|
b = 421235
|
||||||
|
x = X()
|
||||||
|
self.assertEqual(x._objects, None)
|
||||||
|
x.a = a
|
||||||
|
x.b = b
|
||||||
|
self.assertEqual(x._objects, None)
|
||||||
|
|
||||||
|
def test_embedded_structs(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_int), ("b", c_int)]
|
||||||
|
|
||||||
|
class Y(Structure):
|
||||||
|
_fields_ = [("x", X), ("y", X)]
|
||||||
|
|
||||||
|
y = Y()
|
||||||
|
self.assertEqual(y._objects, None)
|
||||||
|
|
||||||
|
x1, x2 = X(), X()
|
||||||
|
y.x, y.y = x1, x2
|
||||||
|
self.assertEqual(y._objects, {"0": {}, "1": {}})
|
||||||
|
x1.a, x2.b = 42, 93
|
||||||
|
self.assertEqual(y._objects, {"0": {}, "1": {}})
|
||||||
|
|
||||||
|
def test_xxx(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_char_p), ("b", c_char_p)]
|
||||||
|
|
||||||
|
class Y(Structure):
|
||||||
|
_fields_ = [("x", X), ("y", X)]
|
||||||
|
|
||||||
|
s1 = b"Hello, World"
|
||||||
|
s2 = b"Hallo, Welt"
|
||||||
|
|
||||||
|
x = X()
|
||||||
|
x.a = s1
|
||||||
|
x.b = s2
|
||||||
|
self.assertEqual(x._objects, {"0": s1, "1": s2})
|
||||||
|
|
||||||
|
y = Y()
|
||||||
|
y.x = x
|
||||||
|
self.assertEqual(y._objects, {"0": {"0": s1, "1": s2}})
|
||||||
|
## x = y.x
|
||||||
|
## del y
|
||||||
|
## print x._b_base_._objects
|
||||||
|
|
||||||
|
def test_ptr_struct(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("data", POINTER(c_int))]
|
||||||
|
|
||||||
|
A = c_int*4
|
||||||
|
a = A(11, 22, 33, 44)
|
||||||
|
self.assertEqual(a._objects, None)
|
||||||
|
|
||||||
|
x = X()
|
||||||
|
x.data = a
|
||||||
|
##XXX print x._objects
|
||||||
|
##XXX print x.data[0]
|
||||||
|
##XXX print x.data._objects
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
153
Lib/ctypes/test/test_keeprefs.py
vendored
Normal file
153
Lib/ctypes/test/test_keeprefs.py
vendored
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
from ctypes import *
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
class SimpleTestCase(unittest.TestCase):
|
||||||
|
def test_cint(self):
|
||||||
|
x = c_int()
|
||||||
|
self.assertEqual(x._objects, None)
|
||||||
|
x.value = 42
|
||||||
|
self.assertEqual(x._objects, None)
|
||||||
|
x = c_int(99)
|
||||||
|
self.assertEqual(x._objects, None)
|
||||||
|
|
||||||
|
def test_ccharp(self):
|
||||||
|
x = c_char_p()
|
||||||
|
self.assertEqual(x._objects, None)
|
||||||
|
x.value = b"abc"
|
||||||
|
self.assertEqual(x._objects, b"abc")
|
||||||
|
x = c_char_p(b"spam")
|
||||||
|
self.assertEqual(x._objects, b"spam")
|
||||||
|
|
||||||
|
class StructureTestCase(unittest.TestCase):
|
||||||
|
def test_cint_struct(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_int),
|
||||||
|
("b", c_int)]
|
||||||
|
|
||||||
|
x = X()
|
||||||
|
self.assertEqual(x._objects, None)
|
||||||
|
x.a = 42
|
||||||
|
x.b = 99
|
||||||
|
self.assertEqual(x._objects, None)
|
||||||
|
|
||||||
|
def test_ccharp_struct(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_char_p),
|
||||||
|
("b", c_char_p)]
|
||||||
|
x = X()
|
||||||
|
self.assertEqual(x._objects, None)
|
||||||
|
|
||||||
|
x.a = b"spam"
|
||||||
|
x.b = b"foo"
|
||||||
|
self.assertEqual(x._objects, {"0": b"spam", "1": b"foo"})
|
||||||
|
|
||||||
|
def test_struct_struct(self):
|
||||||
|
class POINT(Structure):
|
||||||
|
_fields_ = [("x", c_int), ("y", c_int)]
|
||||||
|
class RECT(Structure):
|
||||||
|
_fields_ = [("ul", POINT), ("lr", POINT)]
|
||||||
|
|
||||||
|
r = RECT()
|
||||||
|
r.ul.x = 0
|
||||||
|
r.ul.y = 1
|
||||||
|
r.lr.x = 2
|
||||||
|
r.lr.y = 3
|
||||||
|
self.assertEqual(r._objects, None)
|
||||||
|
|
||||||
|
r = RECT()
|
||||||
|
pt = POINT(1, 2)
|
||||||
|
r.ul = pt
|
||||||
|
self.assertEqual(r._objects, {'0': {}})
|
||||||
|
r.ul.x = 22
|
||||||
|
r.ul.y = 44
|
||||||
|
self.assertEqual(r._objects, {'0': {}})
|
||||||
|
r.lr = POINT()
|
||||||
|
self.assertEqual(r._objects, {'0': {}, '1': {}})
|
||||||
|
|
||||||
|
class ArrayTestCase(unittest.TestCase):
|
||||||
|
def test_cint_array(self):
|
||||||
|
INTARR = c_int * 3
|
||||||
|
|
||||||
|
ia = INTARR()
|
||||||
|
self.assertEqual(ia._objects, None)
|
||||||
|
ia[0] = 1
|
||||||
|
ia[1] = 2
|
||||||
|
ia[2] = 3
|
||||||
|
self.assertEqual(ia._objects, None)
|
||||||
|
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("x", c_int),
|
||||||
|
("a", INTARR)]
|
||||||
|
|
||||||
|
x = X()
|
||||||
|
x.x = 1000
|
||||||
|
x.a[0] = 42
|
||||||
|
x.a[1] = 96
|
||||||
|
self.assertEqual(x._objects, None)
|
||||||
|
x.a = ia
|
||||||
|
self.assertEqual(x._objects, {'1': {}})
|
||||||
|
|
||||||
|
class PointerTestCase(unittest.TestCase):
|
||||||
|
def test_p_cint(self):
|
||||||
|
i = c_int(42)
|
||||||
|
x = pointer(i)
|
||||||
|
self.assertEqual(x._objects, {'1': i})
|
||||||
|
|
||||||
|
class DeletePointerTestCase(unittest.TestCase):
|
||||||
|
@unittest.skip('test disabled')
|
||||||
|
def test_X(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("p", POINTER(c_char_p))]
|
||||||
|
x = X()
|
||||||
|
i = c_char_p("abc def")
|
||||||
|
from sys import getrefcount as grc
|
||||||
|
print("2?", grc(i))
|
||||||
|
x.p = pointer(i)
|
||||||
|
print("3?", grc(i))
|
||||||
|
for i in range(320):
|
||||||
|
c_int(99)
|
||||||
|
x.p[0]
|
||||||
|
print(x.p[0])
|
||||||
|
## del x
|
||||||
|
## print "2?", grc(i)
|
||||||
|
## del i
|
||||||
|
import gc
|
||||||
|
gc.collect()
|
||||||
|
for i in range(320):
|
||||||
|
c_int(99)
|
||||||
|
x.p[0]
|
||||||
|
print(x.p[0])
|
||||||
|
print(x.p.contents)
|
||||||
|
## print x._objects
|
||||||
|
|
||||||
|
x.p[0] = "spam spam"
|
||||||
|
## print x.p[0]
|
||||||
|
print("+" * 42)
|
||||||
|
print(x._objects)
|
||||||
|
|
||||||
|
class PointerToStructure(unittest.TestCase):
|
||||||
|
def test(self):
|
||||||
|
class POINT(Structure):
|
||||||
|
_fields_ = [("x", c_int), ("y", c_int)]
|
||||||
|
class RECT(Structure):
|
||||||
|
_fields_ = [("a", POINTER(POINT)),
|
||||||
|
("b", POINTER(POINT))]
|
||||||
|
r = RECT()
|
||||||
|
p1 = POINT(1, 2)
|
||||||
|
|
||||||
|
r.a = pointer(p1)
|
||||||
|
r.b = pointer(p1)
|
||||||
|
## from pprint import pprint as pp
|
||||||
|
## pp(p1._objects)
|
||||||
|
## pp(r._objects)
|
||||||
|
|
||||||
|
r.a[0].x = 42
|
||||||
|
r.a[0].y = 99
|
||||||
|
|
||||||
|
# to avoid leaking when tests are run several times
|
||||||
|
# clean up the types left in the cache.
|
||||||
|
from ctypes import _pointer_type_cache
|
||||||
|
del _pointer_type_cache[POINT]
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
33
Lib/ctypes/test/test_libc.py
vendored
Normal file
33
Lib/ctypes/test/test_libc.py
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
from ctypes import *
|
||||||
|
import _ctypes_test
|
||||||
|
|
||||||
|
lib = CDLL(_ctypes_test.__file__)
|
||||||
|
|
||||||
|
def three_way_cmp(x, y):
|
||||||
|
"""Return -1 if x < y, 0 if x == y and 1 if x > y"""
|
||||||
|
return (x > y) - (x < y)
|
||||||
|
|
||||||
|
class LibTest(unittest.TestCase):
|
||||||
|
def test_sqrt(self):
|
||||||
|
lib.my_sqrt.argtypes = c_double,
|
||||||
|
lib.my_sqrt.restype = c_double
|
||||||
|
self.assertEqual(lib.my_sqrt(4.0), 2.0)
|
||||||
|
import math
|
||||||
|
self.assertEqual(lib.my_sqrt(2.0), math.sqrt(2.0))
|
||||||
|
|
||||||
|
def test_qsort(self):
|
||||||
|
comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char))
|
||||||
|
lib.my_qsort.argtypes = c_void_p, c_size_t, c_size_t, comparefunc
|
||||||
|
lib.my_qsort.restype = None
|
||||||
|
|
||||||
|
def sort(a, b):
|
||||||
|
return three_way_cmp(a[0], b[0])
|
||||||
|
|
||||||
|
chars = create_string_buffer(b"spam, spam, and spam")
|
||||||
|
lib.my_qsort(chars, len(chars)-1, sizeof(c_char), comparefunc(sort))
|
||||||
|
self.assertEqual(chars.raw, b" ,,aaaadmmmnpppsss\x00")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
182
Lib/ctypes/test/test_loading.py
vendored
Normal file
182
Lib/ctypes/test/test_loading.py
vendored
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
from ctypes import *
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
import test.support
|
||||||
|
from test.support import import_helper
|
||||||
|
from test.support import os_helper
|
||||||
|
from ctypes.util import find_library
|
||||||
|
|
||||||
|
libc_name = None
|
||||||
|
|
||||||
|
def setUpModule():
|
||||||
|
global libc_name
|
||||||
|
if os.name == "nt":
|
||||||
|
libc_name = find_library("c")
|
||||||
|
elif sys.platform == "cygwin":
|
||||||
|
libc_name = "cygwin1.dll"
|
||||||
|
else:
|
||||||
|
libc_name = find_library("c")
|
||||||
|
|
||||||
|
if test.support.verbose:
|
||||||
|
print("libc_name is", libc_name)
|
||||||
|
|
||||||
|
class LoaderTest(unittest.TestCase):
|
||||||
|
|
||||||
|
unknowndll = "xxrandomnamexx"
|
||||||
|
|
||||||
|
def test_load(self):
|
||||||
|
if libc_name is None:
|
||||||
|
self.skipTest('could not find libc')
|
||||||
|
CDLL(libc_name)
|
||||||
|
CDLL(os.path.basename(libc_name))
|
||||||
|
self.assertRaises(OSError, CDLL, self.unknowndll)
|
||||||
|
|
||||||
|
def test_load_version(self):
|
||||||
|
if libc_name is None:
|
||||||
|
self.skipTest('could not find libc')
|
||||||
|
if os.path.basename(libc_name) != 'libc.so.6':
|
||||||
|
self.skipTest('wrong libc path for test')
|
||||||
|
cdll.LoadLibrary("libc.so.6")
|
||||||
|
# linux uses version, libc 9 should not exist
|
||||||
|
self.assertRaises(OSError, cdll.LoadLibrary, "libc.so.9")
|
||||||
|
self.assertRaises(OSError, cdll.LoadLibrary, self.unknowndll)
|
||||||
|
|
||||||
|
def test_find(self):
|
||||||
|
for name in ("c", "m"):
|
||||||
|
lib = find_library(name)
|
||||||
|
if lib:
|
||||||
|
cdll.LoadLibrary(lib)
|
||||||
|
CDLL(lib)
|
||||||
|
|
||||||
|
@unittest.skipUnless(os.name == "nt",
|
||||||
|
'test specific to Windows')
|
||||||
|
def test_load_library(self):
|
||||||
|
# CRT is no longer directly loadable. See issue23606 for the
|
||||||
|
# discussion about alternative approaches.
|
||||||
|
#self.assertIsNotNone(libc_name)
|
||||||
|
if test.support.verbose:
|
||||||
|
print(find_library("kernel32"))
|
||||||
|
print(find_library("user32"))
|
||||||
|
|
||||||
|
if os.name == "nt":
|
||||||
|
windll.kernel32.GetModuleHandleW
|
||||||
|
windll["kernel32"].GetModuleHandleW
|
||||||
|
windll.LoadLibrary("kernel32").GetModuleHandleW
|
||||||
|
WinDLL("kernel32").GetModuleHandleW
|
||||||
|
# embedded null character
|
||||||
|
self.assertRaises(ValueError, windll.LoadLibrary, "kernel32\0")
|
||||||
|
|
||||||
|
@unittest.skipUnless(os.name == "nt",
|
||||||
|
'test specific to Windows')
|
||||||
|
def test_load_ordinal_functions(self):
|
||||||
|
import _ctypes_test
|
||||||
|
dll = WinDLL(_ctypes_test.__file__)
|
||||||
|
# We load the same function both via ordinal and name
|
||||||
|
func_ord = dll[2]
|
||||||
|
func_name = dll.GetString
|
||||||
|
# addressof gets the address where the function pointer is stored
|
||||||
|
a_ord = addressof(func_ord)
|
||||||
|
a_name = addressof(func_name)
|
||||||
|
f_ord_addr = c_void_p.from_address(a_ord).value
|
||||||
|
f_name_addr = c_void_p.from_address(a_name).value
|
||||||
|
self.assertEqual(hex(f_ord_addr), hex(f_name_addr))
|
||||||
|
|
||||||
|
self.assertRaises(AttributeError, dll.__getitem__, 1234)
|
||||||
|
|
||||||
|
@unittest.skipUnless(os.name == "nt", 'Windows-specific test')
|
||||||
|
def test_1703286_A(self):
|
||||||
|
from _ctypes import LoadLibrary, FreeLibrary
|
||||||
|
# On winXP 64-bit, advapi32 loads at an address that does
|
||||||
|
# NOT fit into a 32-bit integer. FreeLibrary must be able
|
||||||
|
# to accept this address.
|
||||||
|
|
||||||
|
# These are tests for https://www.python.org/sf/1703286
|
||||||
|
handle = LoadLibrary("advapi32")
|
||||||
|
FreeLibrary(handle)
|
||||||
|
|
||||||
|
@unittest.skipUnless(os.name == "nt", 'Windows-specific test')
|
||||||
|
def test_1703286_B(self):
|
||||||
|
# Since on winXP 64-bit advapi32 loads like described
|
||||||
|
# above, the (arbitrarily selected) CloseEventLog function
|
||||||
|
# also has a high address. 'call_function' should accept
|
||||||
|
# addresses so large.
|
||||||
|
from _ctypes import call_function
|
||||||
|
advapi32 = windll.advapi32
|
||||||
|
# Calling CloseEventLog with a NULL argument should fail,
|
||||||
|
# but the call should not segfault or so.
|
||||||
|
self.assertEqual(0, advapi32.CloseEventLog(None))
|
||||||
|
windll.kernel32.GetProcAddress.argtypes = c_void_p, c_char_p
|
||||||
|
windll.kernel32.GetProcAddress.restype = c_void_p
|
||||||
|
proc = windll.kernel32.GetProcAddress(advapi32._handle,
|
||||||
|
b"CloseEventLog")
|
||||||
|
self.assertTrue(proc)
|
||||||
|
# This is the real test: call the function via 'call_function'
|
||||||
|
self.assertEqual(0, call_function(proc, (None,)))
|
||||||
|
|
||||||
|
@unittest.skipUnless(os.name == "nt",
|
||||||
|
'test specific to Windows')
|
||||||
|
def test_load_dll_with_flags(self):
|
||||||
|
_sqlite3 = import_helper.import_module("_sqlite3")
|
||||||
|
src = _sqlite3.__file__
|
||||||
|
if src.lower().endswith("_d.pyd"):
|
||||||
|
ext = "_d.dll"
|
||||||
|
else:
|
||||||
|
ext = ".dll"
|
||||||
|
|
||||||
|
with os_helper.temp_dir() as tmp:
|
||||||
|
# We copy two files and load _sqlite3.dll (formerly .pyd),
|
||||||
|
# which has a dependency on sqlite3.dll. Then we test
|
||||||
|
# loading it in subprocesses to avoid it starting in memory
|
||||||
|
# for each test.
|
||||||
|
target = os.path.join(tmp, "_sqlite3.dll")
|
||||||
|
shutil.copy(src, target)
|
||||||
|
shutil.copy(os.path.join(os.path.dirname(src), "sqlite3" + ext),
|
||||||
|
os.path.join(tmp, "sqlite3" + ext))
|
||||||
|
|
||||||
|
def should_pass(command):
|
||||||
|
with self.subTest(command):
|
||||||
|
subprocess.check_output(
|
||||||
|
[sys.executable, "-c",
|
||||||
|
"from ctypes import *; import nt;" + command],
|
||||||
|
cwd=tmp
|
||||||
|
)
|
||||||
|
|
||||||
|
def should_fail(command):
|
||||||
|
with self.subTest(command):
|
||||||
|
with self.assertRaises(subprocess.CalledProcessError):
|
||||||
|
subprocess.check_output(
|
||||||
|
[sys.executable, "-c",
|
||||||
|
"from ctypes import *; import nt;" + command],
|
||||||
|
cwd=tmp, stderr=subprocess.STDOUT,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Default load should not find this in CWD
|
||||||
|
should_fail("WinDLL('_sqlite3.dll')")
|
||||||
|
|
||||||
|
# Relative path (but not just filename) should succeed
|
||||||
|
should_pass("WinDLL('./_sqlite3.dll')")
|
||||||
|
|
||||||
|
# Insecure load flags should succeed
|
||||||
|
# Clear the DLL directory to avoid safe search settings propagating
|
||||||
|
should_pass("windll.kernel32.SetDllDirectoryW(None); WinDLL('_sqlite3.dll', winmode=0)")
|
||||||
|
|
||||||
|
# Full path load without DLL_LOAD_DIR shouldn't find dependency
|
||||||
|
should_fail("WinDLL(nt._getfullpathname('_sqlite3.dll'), " +
|
||||||
|
"winmode=nt._LOAD_LIBRARY_SEARCH_SYSTEM32)")
|
||||||
|
|
||||||
|
# Full path load with DLL_LOAD_DIR should succeed
|
||||||
|
should_pass("WinDLL(nt._getfullpathname('_sqlite3.dll'), " +
|
||||||
|
"winmode=nt._LOAD_LIBRARY_SEARCH_SYSTEM32|" +
|
||||||
|
"nt._LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR)")
|
||||||
|
|
||||||
|
# User-specified directory should succeed
|
||||||
|
should_pass("import os; p = os.add_dll_directory(os.getcwd());" +
|
||||||
|
"WinDLL('_sqlite3.dll'); p.close()")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
110
Lib/ctypes/test/test_macholib.py
vendored
Normal file
110
Lib/ctypes/test/test_macholib.py
vendored
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
# Bob Ippolito:
|
||||||
|
#
|
||||||
|
# Ok.. the code to find the filename for __getattr__ should look
|
||||||
|
# something like:
|
||||||
|
#
|
||||||
|
# import os
|
||||||
|
# from macholib.dyld import dyld_find
|
||||||
|
#
|
||||||
|
# def find_lib(name):
|
||||||
|
# possible = ['lib'+name+'.dylib', name+'.dylib',
|
||||||
|
# name+'.framework/'+name]
|
||||||
|
# for dylib in possible:
|
||||||
|
# try:
|
||||||
|
# return os.path.realpath(dyld_find(dylib))
|
||||||
|
# except ValueError:
|
||||||
|
# pass
|
||||||
|
# raise ValueError, "%s not found" % (name,)
|
||||||
|
#
|
||||||
|
# It'll have output like this:
|
||||||
|
#
|
||||||
|
# >>> find_lib('pthread')
|
||||||
|
# '/usr/lib/libSystem.B.dylib'
|
||||||
|
# >>> find_lib('z')
|
||||||
|
# '/usr/lib/libz.1.dylib'
|
||||||
|
# >>> find_lib('IOKit')
|
||||||
|
# '/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit'
|
||||||
|
#
|
||||||
|
# -bob
|
||||||
|
|
||||||
|
from ctypes.macholib.dyld import dyld_find
|
||||||
|
from ctypes.macholib.dylib import dylib_info
|
||||||
|
from ctypes.macholib.framework import framework_info
|
||||||
|
|
||||||
|
def find_lib(name):
|
||||||
|
possible = ['lib'+name+'.dylib', name+'.dylib', name+'.framework/'+name]
|
||||||
|
for dylib in possible:
|
||||||
|
try:
|
||||||
|
return os.path.realpath(dyld_find(dylib))
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
raise ValueError("%s not found" % (name,))
|
||||||
|
|
||||||
|
|
||||||
|
def d(location=None, name=None, shortname=None, version=None, suffix=None):
|
||||||
|
return {'location': location, 'name': name, 'shortname': shortname,
|
||||||
|
'version': version, 'suffix': suffix}
|
||||||
|
|
||||||
|
|
||||||
|
class MachOTest(unittest.TestCase):
|
||||||
|
@unittest.skipUnless(sys.platform == "darwin", 'OSX-specific test')
|
||||||
|
def test_find(self):
|
||||||
|
self.assertEqual(dyld_find('libSystem.dylib'),
|
||||||
|
'/usr/lib/libSystem.dylib')
|
||||||
|
self.assertEqual(dyld_find('System.framework/System'),
|
||||||
|
'/System/Library/Frameworks/System.framework/System')
|
||||||
|
|
||||||
|
# On Mac OS 11, system dylibs are only present in the shared cache,
|
||||||
|
# so symlinks like libpthread.dylib -> libSystem.B.dylib will not
|
||||||
|
# be resolved by dyld_find
|
||||||
|
self.assertIn(find_lib('pthread'),
|
||||||
|
('/usr/lib/libSystem.B.dylib', '/usr/lib/libpthread.dylib'))
|
||||||
|
|
||||||
|
result = find_lib('z')
|
||||||
|
# Issue #21093: dyld default search path includes $HOME/lib and
|
||||||
|
# /usr/local/lib before /usr/lib, which caused test failures if
|
||||||
|
# a local copy of libz exists in one of them. Now ignore the head
|
||||||
|
# of the path.
|
||||||
|
self.assertRegex(result, r".*/lib/libz.*\.dylib")
|
||||||
|
|
||||||
|
self.assertIn(find_lib('IOKit'),
|
||||||
|
('/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit',
|
||||||
|
'/System/Library/Frameworks/IOKit.framework/IOKit'))
|
||||||
|
|
||||||
|
@unittest.skipUnless(sys.platform == "darwin", 'OSX-specific test')
|
||||||
|
def test_info(self):
|
||||||
|
self.assertIsNone(dylib_info('completely/invalid'))
|
||||||
|
self.assertIsNone(dylib_info('completely/invalide_debug'))
|
||||||
|
self.assertEqual(dylib_info('P/Foo.dylib'), d('P', 'Foo.dylib', 'Foo'))
|
||||||
|
self.assertEqual(dylib_info('P/Foo_debug.dylib'),
|
||||||
|
d('P', 'Foo_debug.dylib', 'Foo', suffix='debug'))
|
||||||
|
self.assertEqual(dylib_info('P/Foo.A.dylib'),
|
||||||
|
d('P', 'Foo.A.dylib', 'Foo', 'A'))
|
||||||
|
self.assertEqual(dylib_info('P/Foo_debug.A.dylib'),
|
||||||
|
d('P', 'Foo_debug.A.dylib', 'Foo_debug', 'A'))
|
||||||
|
self.assertEqual(dylib_info('P/Foo.A_debug.dylib'),
|
||||||
|
d('P', 'Foo.A_debug.dylib', 'Foo', 'A', 'debug'))
|
||||||
|
|
||||||
|
@unittest.skipUnless(sys.platform == "darwin", 'OSX-specific test')
|
||||||
|
def test_framework_info(self):
|
||||||
|
self.assertIsNone(framework_info('completely/invalid'))
|
||||||
|
self.assertIsNone(framework_info('completely/invalid/_debug'))
|
||||||
|
self.assertIsNone(framework_info('P/F.framework'))
|
||||||
|
self.assertIsNone(framework_info('P/F.framework/_debug'))
|
||||||
|
self.assertEqual(framework_info('P/F.framework/F'),
|
||||||
|
d('P', 'F.framework/F', 'F'))
|
||||||
|
self.assertEqual(framework_info('P/F.framework/F_debug'),
|
||||||
|
d('P', 'F.framework/F_debug', 'F', suffix='debug'))
|
||||||
|
self.assertIsNone(framework_info('P/F.framework/Versions'))
|
||||||
|
self.assertIsNone(framework_info('P/F.framework/Versions/A'))
|
||||||
|
self.assertEqual(framework_info('P/F.framework/Versions/A/F'),
|
||||||
|
d('P', 'F.framework/Versions/A/F', 'F', 'A'))
|
||||||
|
self.assertEqual(framework_info('P/F.framework/Versions/A/F_debug'),
|
||||||
|
d('P', 'F.framework/Versions/A/F_debug', 'F', 'A', 'debug'))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
79
Lib/ctypes/test/test_memfunctions.py
vendored
Normal file
79
Lib/ctypes/test/test_memfunctions.py
vendored
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import sys
|
||||||
|
from test import support
|
||||||
|
import unittest
|
||||||
|
from ctypes import *
|
||||||
|
from ctypes.test import need_symbol
|
||||||
|
|
||||||
|
class MemFunctionsTest(unittest.TestCase):
|
||||||
|
@unittest.skip('test disabled')
|
||||||
|
def test_overflow(self):
|
||||||
|
# string_at and wstring_at must use the Python calling
|
||||||
|
# convention (which acquires the GIL and checks the Python
|
||||||
|
# error flag). Provoke an error and catch it; see also issue
|
||||||
|
# #3554: <http://bugs.python.org/issue3554>
|
||||||
|
self.assertRaises((OverflowError, MemoryError, SystemError),
|
||||||
|
lambda: wstring_at(u"foo", sys.maxint - 1))
|
||||||
|
self.assertRaises((OverflowError, MemoryError, SystemError),
|
||||||
|
lambda: string_at("foo", sys.maxint - 1))
|
||||||
|
|
||||||
|
def test_memmove(self):
|
||||||
|
# large buffers apparently increase the chance that the memory
|
||||||
|
# is allocated in high address space.
|
||||||
|
a = create_string_buffer(1000000)
|
||||||
|
p = b"Hello, World"
|
||||||
|
result = memmove(a, p, len(p))
|
||||||
|
self.assertEqual(a.value, b"Hello, World")
|
||||||
|
|
||||||
|
self.assertEqual(string_at(result), b"Hello, World")
|
||||||
|
self.assertEqual(string_at(result, 5), b"Hello")
|
||||||
|
self.assertEqual(string_at(result, 16), b"Hello, World\0\0\0\0")
|
||||||
|
self.assertEqual(string_at(result, 0), b"")
|
||||||
|
|
||||||
|
def test_memset(self):
|
||||||
|
a = create_string_buffer(1000000)
|
||||||
|
result = memset(a, ord('x'), 16)
|
||||||
|
self.assertEqual(a.value, b"xxxxxxxxxxxxxxxx")
|
||||||
|
|
||||||
|
self.assertEqual(string_at(result), b"xxxxxxxxxxxxxxxx")
|
||||||
|
self.assertEqual(string_at(a), b"xxxxxxxxxxxxxxxx")
|
||||||
|
self.assertEqual(string_at(a, 20), b"xxxxxxxxxxxxxxxx\0\0\0\0")
|
||||||
|
|
||||||
|
def test_cast(self):
|
||||||
|
a = (c_ubyte * 32)(*map(ord, "abcdef"))
|
||||||
|
self.assertEqual(cast(a, c_char_p).value, b"abcdef")
|
||||||
|
self.assertEqual(cast(a, POINTER(c_byte))[:7],
|
||||||
|
[97, 98, 99, 100, 101, 102, 0])
|
||||||
|
self.assertEqual(cast(a, POINTER(c_byte))[:7:],
|
||||||
|
[97, 98, 99, 100, 101, 102, 0])
|
||||||
|
self.assertEqual(cast(a, POINTER(c_byte))[6:-1:-1],
|
||||||
|
[0, 102, 101, 100, 99, 98, 97])
|
||||||
|
self.assertEqual(cast(a, POINTER(c_byte))[:7:2],
|
||||||
|
[97, 99, 101, 0])
|
||||||
|
self.assertEqual(cast(a, POINTER(c_byte))[:7:7],
|
||||||
|
[97])
|
||||||
|
|
||||||
|
@support.refcount_test
|
||||||
|
def test_string_at(self):
|
||||||
|
s = string_at(b"foo bar")
|
||||||
|
# XXX The following may be wrong, depending on how Python
|
||||||
|
# manages string instances
|
||||||
|
self.assertEqual(2, sys.getrefcount(s))
|
||||||
|
self.assertTrue(s, "foo bar")
|
||||||
|
|
||||||
|
self.assertEqual(string_at(b"foo bar", 7), b"foo bar")
|
||||||
|
self.assertEqual(string_at(b"foo bar", 3), b"foo")
|
||||||
|
|
||||||
|
@need_symbol('create_unicode_buffer')
|
||||||
|
def test_wstring_at(self):
|
||||||
|
p = create_unicode_buffer("Hello, World")
|
||||||
|
a = create_unicode_buffer(1000000)
|
||||||
|
result = memmove(a, p, len(p) * sizeof(c_wchar))
|
||||||
|
self.assertEqual(a.value, "Hello, World")
|
||||||
|
|
||||||
|
self.assertEqual(wstring_at(a), "Hello, World")
|
||||||
|
self.assertEqual(wstring_at(a, 5), "Hello")
|
||||||
|
self.assertEqual(wstring_at(a, 16), "Hello, World\0\0\0\0")
|
||||||
|
self.assertEqual(wstring_at(a, 0), "")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
295
Lib/ctypes/test/test_numbers.py
vendored
Normal file
295
Lib/ctypes/test/test_numbers.py
vendored
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
from ctypes import *
|
||||||
|
import unittest
|
||||||
|
import struct
|
||||||
|
|
||||||
|
def valid_ranges(*types):
|
||||||
|
# given a sequence of numeric types, collect their _type_
|
||||||
|
# attribute, which is a single format character compatible with
|
||||||
|
# the struct module, use the struct module to calculate the
|
||||||
|
# minimum and maximum value allowed for this format.
|
||||||
|
# Returns a list of (min, max) values.
|
||||||
|
result = []
|
||||||
|
for t in types:
|
||||||
|
fmt = t._type_
|
||||||
|
size = struct.calcsize(fmt)
|
||||||
|
a = struct.unpack(fmt, (b"\x00"*32)[:size])[0]
|
||||||
|
b = struct.unpack(fmt, (b"\xFF"*32)[:size])[0]
|
||||||
|
c = struct.unpack(fmt, (b"\x7F"+b"\x00"*32)[:size])[0]
|
||||||
|
d = struct.unpack(fmt, (b"\x80"+b"\xFF"*32)[:size])[0]
|
||||||
|
result.append((min(a, b, c, d), max(a, b, c, d)))
|
||||||
|
return result
|
||||||
|
|
||||||
|
ArgType = type(byref(c_int(0)))
|
||||||
|
|
||||||
|
unsigned_types = [c_ubyte, c_ushort, c_uint, c_ulong]
|
||||||
|
signed_types = [c_byte, c_short, c_int, c_long, c_longlong]
|
||||||
|
|
||||||
|
bool_types = []
|
||||||
|
|
||||||
|
float_types = [c_double, c_float]
|
||||||
|
|
||||||
|
try:
|
||||||
|
c_ulonglong
|
||||||
|
c_longlong
|
||||||
|
except NameError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
unsigned_types.append(c_ulonglong)
|
||||||
|
signed_types.append(c_longlong)
|
||||||
|
|
||||||
|
try:
|
||||||
|
c_bool
|
||||||
|
except NameError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
bool_types.append(c_bool)
|
||||||
|
|
||||||
|
unsigned_ranges = valid_ranges(*unsigned_types)
|
||||||
|
signed_ranges = valid_ranges(*signed_types)
|
||||||
|
bool_values = [True, False, 0, 1, -1, 5000, 'test', [], [1]]
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
class NumberTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_default_init(self):
|
||||||
|
# default values are set to zero
|
||||||
|
for t in signed_types + unsigned_types + float_types:
|
||||||
|
self.assertEqual(t().value, 0)
|
||||||
|
|
||||||
|
def test_unsigned_values(self):
|
||||||
|
# the value given to the constructor is available
|
||||||
|
# as the 'value' attribute
|
||||||
|
for t, (l, h) in zip(unsigned_types, unsigned_ranges):
|
||||||
|
self.assertEqual(t(l).value, l)
|
||||||
|
self.assertEqual(t(h).value, h)
|
||||||
|
|
||||||
|
def test_signed_values(self):
|
||||||
|
# see above
|
||||||
|
for t, (l, h) in zip(signed_types, signed_ranges):
|
||||||
|
self.assertEqual(t(l).value, l)
|
||||||
|
self.assertEqual(t(h).value, h)
|
||||||
|
|
||||||
|
def test_bool_values(self):
|
||||||
|
from operator import truth
|
||||||
|
for t, v in zip(bool_types, bool_values):
|
||||||
|
self.assertEqual(t(v).value, truth(v))
|
||||||
|
|
||||||
|
def test_typeerror(self):
|
||||||
|
# Only numbers are allowed in the constructor,
|
||||||
|
# otherwise TypeError is raised
|
||||||
|
for t in signed_types + unsigned_types + float_types:
|
||||||
|
self.assertRaises(TypeError, t, "")
|
||||||
|
self.assertRaises(TypeError, t, None)
|
||||||
|
|
||||||
|
@unittest.skip('test disabled')
|
||||||
|
def test_valid_ranges(self):
|
||||||
|
# invalid values of the correct type
|
||||||
|
# raise ValueError (not OverflowError)
|
||||||
|
for t, (l, h) in zip(unsigned_types, unsigned_ranges):
|
||||||
|
self.assertRaises(ValueError, t, l-1)
|
||||||
|
self.assertRaises(ValueError, t, h+1)
|
||||||
|
|
||||||
|
def test_from_param(self):
|
||||||
|
# the from_param class method attribute always
|
||||||
|
# returns PyCArgObject instances
|
||||||
|
for t in signed_types + unsigned_types + float_types:
|
||||||
|
self.assertEqual(ArgType, type(t.from_param(0)))
|
||||||
|
|
||||||
|
def test_byref(self):
|
||||||
|
# calling byref returns also a PyCArgObject instance
|
||||||
|
for t in signed_types + unsigned_types + float_types + bool_types:
|
||||||
|
parm = byref(t())
|
||||||
|
self.assertEqual(ArgType, type(parm))
|
||||||
|
|
||||||
|
|
||||||
|
def test_floats(self):
|
||||||
|
# c_float and c_double can be created from
|
||||||
|
# Python int and float
|
||||||
|
class FloatLike(object):
|
||||||
|
def __float__(self):
|
||||||
|
return 2.0
|
||||||
|
f = FloatLike()
|
||||||
|
for t in float_types:
|
||||||
|
self.assertEqual(t(2.0).value, 2.0)
|
||||||
|
self.assertEqual(t(2).value, 2.0)
|
||||||
|
self.assertEqual(t(2).value, 2.0)
|
||||||
|
self.assertEqual(t(f).value, 2.0)
|
||||||
|
|
||||||
|
def test_integers(self):
|
||||||
|
class FloatLike(object):
|
||||||
|
def __float__(self):
|
||||||
|
return 2.0
|
||||||
|
f = FloatLike()
|
||||||
|
class IntLike(object):
|
||||||
|
def __int__(self):
|
||||||
|
return 2
|
||||||
|
d = IntLike()
|
||||||
|
class IndexLike(object):
|
||||||
|
def __index__(self):
|
||||||
|
return 2
|
||||||
|
i = IndexLike()
|
||||||
|
# integers cannot be constructed from floats,
|
||||||
|
# but from integer-like objects
|
||||||
|
for t in signed_types + unsigned_types:
|
||||||
|
self.assertRaises(TypeError, t, 3.14)
|
||||||
|
self.assertRaises(TypeError, t, f)
|
||||||
|
self.assertRaises(TypeError, t, d)
|
||||||
|
self.assertEqual(t(i).value, 2)
|
||||||
|
|
||||||
|
def test_sizes(self):
|
||||||
|
for t in signed_types + unsigned_types + float_types + bool_types:
|
||||||
|
try:
|
||||||
|
size = struct.calcsize(t._type_)
|
||||||
|
except struct.error:
|
||||||
|
continue
|
||||||
|
# sizeof of the type...
|
||||||
|
self.assertEqual(sizeof(t), size)
|
||||||
|
# and sizeof of an instance
|
||||||
|
self.assertEqual(sizeof(t()), size)
|
||||||
|
|
||||||
|
def test_alignments(self):
|
||||||
|
for t in signed_types + unsigned_types + float_types:
|
||||||
|
code = t._type_ # the typecode
|
||||||
|
align = struct.calcsize("c%c" % code) - struct.calcsize(code)
|
||||||
|
|
||||||
|
# alignment of the type...
|
||||||
|
self.assertEqual((code, alignment(t)),
|
||||||
|
(code, align))
|
||||||
|
# and alignment of an instance
|
||||||
|
self.assertEqual((code, alignment(t())),
|
||||||
|
(code, align))
|
||||||
|
|
||||||
|
def test_int_from_address(self):
|
||||||
|
from array import array
|
||||||
|
for t in signed_types + unsigned_types:
|
||||||
|
# the array module doesn't support all format codes
|
||||||
|
# (no 'q' or 'Q')
|
||||||
|
try:
|
||||||
|
array(t._type_)
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
a = array(t._type_, [100])
|
||||||
|
|
||||||
|
# v now is an integer at an 'external' memory location
|
||||||
|
v = t.from_address(a.buffer_info()[0])
|
||||||
|
self.assertEqual(v.value, a[0])
|
||||||
|
self.assertEqual(type(v), t)
|
||||||
|
|
||||||
|
# changing the value at the memory location changes v's value also
|
||||||
|
a[0] = 42
|
||||||
|
self.assertEqual(v.value, a[0])
|
||||||
|
|
||||||
|
|
||||||
|
def test_float_from_address(self):
|
||||||
|
from array import array
|
||||||
|
for t in float_types:
|
||||||
|
a = array(t._type_, [3.14])
|
||||||
|
v = t.from_address(a.buffer_info()[0])
|
||||||
|
self.assertEqual(v.value, a[0])
|
||||||
|
self.assertIs(type(v), t)
|
||||||
|
a[0] = 2.3456e17
|
||||||
|
self.assertEqual(v.value, a[0])
|
||||||
|
self.assertIs(type(v), t)
|
||||||
|
|
||||||
|
def test_char_from_address(self):
|
||||||
|
from ctypes import c_char
|
||||||
|
from array import array
|
||||||
|
|
||||||
|
a = array('b', [0])
|
||||||
|
a[0] = ord('x')
|
||||||
|
v = c_char.from_address(a.buffer_info()[0])
|
||||||
|
self.assertEqual(v.value, b'x')
|
||||||
|
self.assertIs(type(v), c_char)
|
||||||
|
|
||||||
|
a[0] = ord('?')
|
||||||
|
self.assertEqual(v.value, b'?')
|
||||||
|
|
||||||
|
# array does not support c_bool / 't'
|
||||||
|
@unittest.skip('test disabled')
|
||||||
|
def test_bool_from_address(self):
|
||||||
|
from ctypes import c_bool
|
||||||
|
from array import array
|
||||||
|
a = array(c_bool._type_, [True])
|
||||||
|
v = t.from_address(a.buffer_info()[0])
|
||||||
|
self.assertEqual(v.value, a[0])
|
||||||
|
self.assertEqual(type(v) is t)
|
||||||
|
a[0] = False
|
||||||
|
self.assertEqual(v.value, a[0])
|
||||||
|
self.assertEqual(type(v) is t)
|
||||||
|
|
||||||
|
def test_init(self):
|
||||||
|
# c_int() can be initialized from Python's int, and c_int.
|
||||||
|
# Not from c_long or so, which seems strange, abc should
|
||||||
|
# probably be changed:
|
||||||
|
self.assertRaises(TypeError, c_int, c_long(42))
|
||||||
|
|
||||||
|
def test_float_overflow(self):
|
||||||
|
import sys
|
||||||
|
big_int = int(sys.float_info.max) * 2
|
||||||
|
for t in float_types + [c_longdouble]:
|
||||||
|
self.assertRaises(OverflowError, t, big_int)
|
||||||
|
if (hasattr(t, "__ctype_be__")):
|
||||||
|
self.assertRaises(OverflowError, t.__ctype_be__, big_int)
|
||||||
|
if (hasattr(t, "__ctype_le__")):
|
||||||
|
self.assertRaises(OverflowError, t.__ctype_le__, big_int)
|
||||||
|
|
||||||
|
@unittest.skip('test disabled')
|
||||||
|
def test_perf(self):
|
||||||
|
check_perf()
|
||||||
|
|
||||||
|
from ctypes import _SimpleCData
|
||||||
|
class c_int_S(_SimpleCData):
|
||||||
|
_type_ = "i"
|
||||||
|
__slots__ = []
|
||||||
|
|
||||||
|
def run_test(rep, msg, func, arg=None):
|
||||||
|
## items = [None] * rep
|
||||||
|
items = range(rep)
|
||||||
|
from time import perf_counter as clock
|
||||||
|
if arg is not None:
|
||||||
|
start = clock()
|
||||||
|
for i in items:
|
||||||
|
func(arg); func(arg); func(arg); func(arg); func(arg)
|
||||||
|
stop = clock()
|
||||||
|
else:
|
||||||
|
start = clock()
|
||||||
|
for i in items:
|
||||||
|
func(); func(); func(); func(); func()
|
||||||
|
stop = clock()
|
||||||
|
print("%15s: %.2f us" % (msg, ((stop-start)*1e6/5/rep)))
|
||||||
|
|
||||||
|
def check_perf():
|
||||||
|
# Construct 5 objects
|
||||||
|
from ctypes import c_int
|
||||||
|
|
||||||
|
REP = 200000
|
||||||
|
|
||||||
|
run_test(REP, "int()", int)
|
||||||
|
run_test(REP, "int(999)", int)
|
||||||
|
run_test(REP, "c_int()", c_int)
|
||||||
|
run_test(REP, "c_int(999)", c_int)
|
||||||
|
run_test(REP, "c_int_S()", c_int_S)
|
||||||
|
run_test(REP, "c_int_S(999)", c_int_S)
|
||||||
|
|
||||||
|
# Python 2.3 -OO, win2k, P4 700 MHz:
|
||||||
|
#
|
||||||
|
# int(): 0.87 us
|
||||||
|
# int(999): 0.87 us
|
||||||
|
# c_int(): 3.35 us
|
||||||
|
# c_int(999): 3.34 us
|
||||||
|
# c_int_S(): 3.23 us
|
||||||
|
# c_int_S(999): 3.24 us
|
||||||
|
|
||||||
|
# Python 2.2 -OO, win2k, P4 700 MHz:
|
||||||
|
#
|
||||||
|
# int(): 0.89 us
|
||||||
|
# int(999): 0.89 us
|
||||||
|
# c_int(): 9.99 us
|
||||||
|
# c_int(999): 10.02 us
|
||||||
|
# c_int_S(): 9.87 us
|
||||||
|
# c_int_S(999): 9.85 us
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
## check_perf()
|
||||||
|
unittest.main()
|
||||||
67
Lib/ctypes/test/test_objects.py
vendored
Normal file
67
Lib/ctypes/test/test_objects.py
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
r'''
|
||||||
|
This tests the '_objects' attribute of ctypes instances. '_objects'
|
||||||
|
holds references to objects that must be kept alive as long as the
|
||||||
|
ctypes instance, to make sure that the memory buffer is valid.
|
||||||
|
|
||||||
|
WARNING: The '_objects' attribute is exposed ONLY for debugging ctypes itself,
|
||||||
|
it MUST NEVER BE MODIFIED!
|
||||||
|
|
||||||
|
'_objects' is initialized to a dictionary on first use, before that it
|
||||||
|
is None.
|
||||||
|
|
||||||
|
Here is an array of string pointers:
|
||||||
|
|
||||||
|
>>> from ctypes import *
|
||||||
|
>>> array = (c_char_p * 5)()
|
||||||
|
>>> print(array._objects)
|
||||||
|
None
|
||||||
|
>>>
|
||||||
|
|
||||||
|
The memory block stores pointers to strings, and the strings itself
|
||||||
|
assigned from Python must be kept.
|
||||||
|
|
||||||
|
>>> array[4] = b'foo bar'
|
||||||
|
>>> array._objects
|
||||||
|
{'4': b'foo bar'}
|
||||||
|
>>> array[4]
|
||||||
|
b'foo bar'
|
||||||
|
>>>
|
||||||
|
|
||||||
|
It gets more complicated when the ctypes instance itself is contained
|
||||||
|
in a 'base' object.
|
||||||
|
|
||||||
|
>>> class X(Structure):
|
||||||
|
... _fields_ = [("x", c_int), ("y", c_int), ("array", c_char_p * 5)]
|
||||||
|
...
|
||||||
|
>>> x = X()
|
||||||
|
>>> print(x._objects)
|
||||||
|
None
|
||||||
|
>>>
|
||||||
|
|
||||||
|
The'array' attribute of the 'x' object shares part of the memory buffer
|
||||||
|
of 'x' ('_b_base_' is either None, or the root object owning the memory block):
|
||||||
|
|
||||||
|
>>> print(x.array._b_base_) # doctest: +ELLIPSIS
|
||||||
|
<ctypes.test.test_objects.X object at 0x...>
|
||||||
|
>>>
|
||||||
|
|
||||||
|
>>> x.array[0] = b'spam spam spam'
|
||||||
|
>>> x._objects
|
||||||
|
{'0:2': b'spam spam spam'}
|
||||||
|
>>> x.array._b_base_._objects
|
||||||
|
{'0:2': b'spam spam spam'}
|
||||||
|
>>>
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
import unittest, doctest
|
||||||
|
|
||||||
|
import ctypes.test.test_objects
|
||||||
|
|
||||||
|
class TestCase(unittest.TestCase):
|
||||||
|
def test(self):
|
||||||
|
failures, tests = doctest.testmod(ctypes.test.test_objects)
|
||||||
|
self.assertFalse(failures, 'doctests failed, see output above')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
doctest.testmod(ctypes.test.test_objects)
|
||||||
250
Lib/ctypes/test/test_parameters.py
vendored
Normal file
250
Lib/ctypes/test/test_parameters.py
vendored
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
import unittest
|
||||||
|
from ctypes.test import need_symbol
|
||||||
|
import test.support
|
||||||
|
|
||||||
|
class SimpleTypesTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
import ctypes
|
||||||
|
try:
|
||||||
|
from _ctypes import set_conversion_mode
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.prev_conv_mode = set_conversion_mode("ascii", "strict")
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
try:
|
||||||
|
from _ctypes import set_conversion_mode
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
set_conversion_mode(*self.prev_conv_mode)
|
||||||
|
|
||||||
|
def test_subclasses(self):
|
||||||
|
from ctypes import c_void_p, c_char_p
|
||||||
|
# ctypes 0.9.5 and before did overwrite from_param in SimpleType_new
|
||||||
|
class CVOIDP(c_void_p):
|
||||||
|
def from_param(cls, value):
|
||||||
|
return value * 2
|
||||||
|
from_param = classmethod(from_param)
|
||||||
|
|
||||||
|
class CCHARP(c_char_p):
|
||||||
|
def from_param(cls, value):
|
||||||
|
return value * 4
|
||||||
|
from_param = classmethod(from_param)
|
||||||
|
|
||||||
|
self.assertEqual(CVOIDP.from_param("abc"), "abcabc")
|
||||||
|
self.assertEqual(CCHARP.from_param("abc"), "abcabcabcabc")
|
||||||
|
|
||||||
|
@need_symbol('c_wchar_p')
|
||||||
|
def test_subclasses_c_wchar_p(self):
|
||||||
|
from ctypes import c_wchar_p
|
||||||
|
|
||||||
|
class CWCHARP(c_wchar_p):
|
||||||
|
def from_param(cls, value):
|
||||||
|
return value * 3
|
||||||
|
from_param = classmethod(from_param)
|
||||||
|
|
||||||
|
self.assertEqual(CWCHARP.from_param("abc"), "abcabcabc")
|
||||||
|
|
||||||
|
# XXX Replace by c_char_p tests
|
||||||
|
def test_cstrings(self):
|
||||||
|
from ctypes import c_char_p
|
||||||
|
|
||||||
|
# c_char_p.from_param on a Python String packs the string
|
||||||
|
# into a cparam object
|
||||||
|
s = b"123"
|
||||||
|
self.assertIs(c_char_p.from_param(s)._obj, s)
|
||||||
|
|
||||||
|
# new in 0.9.1: convert (encode) unicode to ascii
|
||||||
|
self.assertEqual(c_char_p.from_param(b"123")._obj, b"123")
|
||||||
|
self.assertRaises(TypeError, c_char_p.from_param, "123\377")
|
||||||
|
self.assertRaises(TypeError, c_char_p.from_param, 42)
|
||||||
|
|
||||||
|
# calling c_char_p.from_param with a c_char_p instance
|
||||||
|
# returns the argument itself:
|
||||||
|
a = c_char_p(b"123")
|
||||||
|
self.assertIs(c_char_p.from_param(a), a)
|
||||||
|
|
||||||
|
@need_symbol('c_wchar_p')
|
||||||
|
def test_cw_strings(self):
|
||||||
|
from ctypes import c_wchar_p
|
||||||
|
|
||||||
|
c_wchar_p.from_param("123")
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, c_wchar_p.from_param, 42)
|
||||||
|
self.assertRaises(TypeError, c_wchar_p.from_param, b"123\377")
|
||||||
|
|
||||||
|
pa = c_wchar_p.from_param(c_wchar_p("123"))
|
||||||
|
self.assertEqual(type(pa), c_wchar_p)
|
||||||
|
|
||||||
|
def test_int_pointers(self):
|
||||||
|
from ctypes import c_short, c_uint, c_int, c_long, POINTER, pointer
|
||||||
|
LPINT = POINTER(c_int)
|
||||||
|
|
||||||
|
## p = pointer(c_int(42))
|
||||||
|
## x = LPINT.from_param(p)
|
||||||
|
x = LPINT.from_param(pointer(c_int(42)))
|
||||||
|
self.assertEqual(x.contents.value, 42)
|
||||||
|
self.assertEqual(LPINT(c_int(42)).contents.value, 42)
|
||||||
|
|
||||||
|
self.assertEqual(LPINT.from_param(None), None)
|
||||||
|
|
||||||
|
if c_int != c_long:
|
||||||
|
self.assertRaises(TypeError, LPINT.from_param, pointer(c_long(42)))
|
||||||
|
self.assertRaises(TypeError, LPINT.from_param, pointer(c_uint(42)))
|
||||||
|
self.assertRaises(TypeError, LPINT.from_param, pointer(c_short(42)))
|
||||||
|
|
||||||
|
def test_byref_pointer(self):
|
||||||
|
# The from_param class method of POINTER(typ) classes accepts what is
|
||||||
|
# returned by byref(obj), it type(obj) == typ
|
||||||
|
from ctypes import c_short, c_uint, c_int, c_long, POINTER, byref
|
||||||
|
LPINT = POINTER(c_int)
|
||||||
|
|
||||||
|
LPINT.from_param(byref(c_int(42)))
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, LPINT.from_param, byref(c_short(22)))
|
||||||
|
if c_int != c_long:
|
||||||
|
self.assertRaises(TypeError, LPINT.from_param, byref(c_long(22)))
|
||||||
|
self.assertRaises(TypeError, LPINT.from_param, byref(c_uint(22)))
|
||||||
|
|
||||||
|
def test_byref_pointerpointer(self):
|
||||||
|
# See above
|
||||||
|
from ctypes import c_short, c_uint, c_int, c_long, pointer, POINTER, byref
|
||||||
|
|
||||||
|
LPLPINT = POINTER(POINTER(c_int))
|
||||||
|
LPLPINT.from_param(byref(pointer(c_int(42))))
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, LPLPINT.from_param, byref(pointer(c_short(22))))
|
||||||
|
if c_int != c_long:
|
||||||
|
self.assertRaises(TypeError, LPLPINT.from_param, byref(pointer(c_long(22))))
|
||||||
|
self.assertRaises(TypeError, LPLPINT.from_param, byref(pointer(c_uint(22))))
|
||||||
|
|
||||||
|
def test_array_pointers(self):
|
||||||
|
from ctypes import c_short, c_uint, c_int, c_long, POINTER
|
||||||
|
INTARRAY = c_int * 3
|
||||||
|
ia = INTARRAY()
|
||||||
|
self.assertEqual(len(ia), 3)
|
||||||
|
self.assertEqual([ia[i] for i in range(3)], [0, 0, 0])
|
||||||
|
|
||||||
|
# Pointers are only compatible with arrays containing items of
|
||||||
|
# the same type!
|
||||||
|
LPINT = POINTER(c_int)
|
||||||
|
LPINT.from_param((c_int*3)())
|
||||||
|
self.assertRaises(TypeError, LPINT.from_param, c_short*3)
|
||||||
|
self.assertRaises(TypeError, LPINT.from_param, c_long*3)
|
||||||
|
self.assertRaises(TypeError, LPINT.from_param, c_uint*3)
|
||||||
|
|
||||||
|
def test_noctypes_argtype(self):
|
||||||
|
import _ctypes_test
|
||||||
|
from ctypes import CDLL, c_void_p, ArgumentError
|
||||||
|
|
||||||
|
func = CDLL(_ctypes_test.__file__)._testfunc_p_p
|
||||||
|
func.restype = c_void_p
|
||||||
|
# TypeError: has no from_param method
|
||||||
|
self.assertRaises(TypeError, setattr, func, "argtypes", (object,))
|
||||||
|
|
||||||
|
class Adapter(object):
|
||||||
|
def from_param(cls, obj):
|
||||||
|
return None
|
||||||
|
|
||||||
|
func.argtypes = (Adapter(),)
|
||||||
|
self.assertEqual(func(None), None)
|
||||||
|
self.assertEqual(func(object()), None)
|
||||||
|
|
||||||
|
class Adapter(object):
|
||||||
|
def from_param(cls, obj):
|
||||||
|
return obj
|
||||||
|
|
||||||
|
func.argtypes = (Adapter(),)
|
||||||
|
# don't know how to convert parameter 1
|
||||||
|
self.assertRaises(ArgumentError, func, object())
|
||||||
|
self.assertEqual(func(c_void_p(42)), 42)
|
||||||
|
|
||||||
|
class Adapter(object):
|
||||||
|
def from_param(cls, obj):
|
||||||
|
raise ValueError(obj)
|
||||||
|
|
||||||
|
func.argtypes = (Adapter(),)
|
||||||
|
# ArgumentError: argument 1: ValueError: 99
|
||||||
|
self.assertRaises(ArgumentError, func, 99)
|
||||||
|
|
||||||
|
def test_abstract(self):
|
||||||
|
from ctypes import (Array, Structure, Union, _Pointer,
|
||||||
|
_SimpleCData, _CFuncPtr)
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, Array.from_param, 42)
|
||||||
|
self.assertRaises(TypeError, Structure.from_param, 42)
|
||||||
|
self.assertRaises(TypeError, Union.from_param, 42)
|
||||||
|
self.assertRaises(TypeError, _CFuncPtr.from_param, 42)
|
||||||
|
self.assertRaises(TypeError, _Pointer.from_param, 42)
|
||||||
|
self.assertRaises(TypeError, _SimpleCData.from_param, 42)
|
||||||
|
|
||||||
|
@test.support.cpython_only
|
||||||
|
def test_issue31311(self):
|
||||||
|
# __setstate__ should neither raise a SystemError nor crash in case
|
||||||
|
# of a bad __dict__.
|
||||||
|
from ctypes import Structure
|
||||||
|
|
||||||
|
class BadStruct(Structure):
|
||||||
|
@property
|
||||||
|
def __dict__(self):
|
||||||
|
pass
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
BadStruct().__setstate__({}, b'foo')
|
||||||
|
|
||||||
|
class WorseStruct(Structure):
|
||||||
|
@property
|
||||||
|
def __dict__(self):
|
||||||
|
1/0
|
||||||
|
with self.assertRaises(ZeroDivisionError):
|
||||||
|
WorseStruct().__setstate__({}, b'foo')
|
||||||
|
|
||||||
|
def test_parameter_repr(self):
|
||||||
|
from ctypes import (
|
||||||
|
c_bool,
|
||||||
|
c_char,
|
||||||
|
c_wchar,
|
||||||
|
c_byte,
|
||||||
|
c_ubyte,
|
||||||
|
c_short,
|
||||||
|
c_ushort,
|
||||||
|
c_int,
|
||||||
|
c_uint,
|
||||||
|
c_long,
|
||||||
|
c_ulong,
|
||||||
|
c_longlong,
|
||||||
|
c_ulonglong,
|
||||||
|
c_float,
|
||||||
|
c_double,
|
||||||
|
c_longdouble,
|
||||||
|
c_char_p,
|
||||||
|
c_wchar_p,
|
||||||
|
c_void_p,
|
||||||
|
)
|
||||||
|
self.assertRegex(repr(c_bool.from_param(True)), r"^<cparam '\?' at 0x[A-Fa-f0-9]+>$")
|
||||||
|
self.assertEqual(repr(c_char.from_param(97)), "<cparam 'c' ('a')>")
|
||||||
|
self.assertRegex(repr(c_wchar.from_param('a')), r"^<cparam 'u' at 0x[A-Fa-f0-9]+>$")
|
||||||
|
self.assertEqual(repr(c_byte.from_param(98)), "<cparam 'b' (98)>")
|
||||||
|
self.assertEqual(repr(c_ubyte.from_param(98)), "<cparam 'B' (98)>")
|
||||||
|
self.assertEqual(repr(c_short.from_param(511)), "<cparam 'h' (511)>")
|
||||||
|
self.assertEqual(repr(c_ushort.from_param(511)), "<cparam 'H' (511)>")
|
||||||
|
self.assertRegex(repr(c_int.from_param(20000)), r"^<cparam '[li]' \(20000\)>$")
|
||||||
|
self.assertRegex(repr(c_uint.from_param(20000)), r"^<cparam '[LI]' \(20000\)>$")
|
||||||
|
self.assertRegex(repr(c_long.from_param(20000)), r"^<cparam '[li]' \(20000\)>$")
|
||||||
|
self.assertRegex(repr(c_ulong.from_param(20000)), r"^<cparam '[LI]' \(20000\)>$")
|
||||||
|
self.assertRegex(repr(c_longlong.from_param(20000)), r"^<cparam '[liq]' \(20000\)>$")
|
||||||
|
self.assertRegex(repr(c_ulonglong.from_param(20000)), r"^<cparam '[LIQ]' \(20000\)>$")
|
||||||
|
self.assertEqual(repr(c_float.from_param(1.5)), "<cparam 'f' (1.5)>")
|
||||||
|
self.assertEqual(repr(c_double.from_param(1.5)), "<cparam 'd' (1.5)>")
|
||||||
|
self.assertEqual(repr(c_double.from_param(1e300)), "<cparam 'd' (1e+300)>")
|
||||||
|
self.assertRegex(repr(c_longdouble.from_param(1.5)), r"^<cparam ('d' \(1.5\)|'g' at 0x[A-Fa-f0-9]+)>$")
|
||||||
|
self.assertRegex(repr(c_char_p.from_param(b'hihi')), r"^<cparam 'z' \(0x[A-Fa-f0-9]+\)>$")
|
||||||
|
self.assertRegex(repr(c_wchar_p.from_param('hihi')), r"^<cparam 'Z' \(0x[A-Fa-f0-9]+\)>$")
|
||||||
|
self.assertRegex(repr(c_void_p.from_param(0x12)), r"^<cparam 'P' \(0x0*12\)>$")
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
235
Lib/ctypes/test/test_pep3118.py
vendored
Normal file
235
Lib/ctypes/test/test_pep3118.py
vendored
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
import unittest
|
||||||
|
from ctypes import *
|
||||||
|
import re, sys
|
||||||
|
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
THIS_ENDIAN = "<"
|
||||||
|
OTHER_ENDIAN = ">"
|
||||||
|
else:
|
||||||
|
THIS_ENDIAN = ">"
|
||||||
|
OTHER_ENDIAN = "<"
|
||||||
|
|
||||||
|
def normalize(format):
|
||||||
|
# Remove current endian specifier and white space from a format
|
||||||
|
# string
|
||||||
|
if format is None:
|
||||||
|
return ""
|
||||||
|
format = format.replace(OTHER_ENDIAN, THIS_ENDIAN)
|
||||||
|
return re.sub(r"\s", "", format)
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_native_types(self):
|
||||||
|
for tp, fmt, shape, itemtp in native_types:
|
||||||
|
ob = tp()
|
||||||
|
v = memoryview(ob)
|
||||||
|
try:
|
||||||
|
self.assertEqual(normalize(v.format), normalize(fmt))
|
||||||
|
if shape:
|
||||||
|
self.assertEqual(len(v), shape[0])
|
||||||
|
else:
|
||||||
|
self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob))
|
||||||
|
self.assertEqual(v.itemsize, sizeof(itemtp))
|
||||||
|
self.assertEqual(v.shape, shape)
|
||||||
|
# XXX Issue #12851: PyCData_NewGetBuffer() must provide strides
|
||||||
|
# if requested. memoryview currently reconstructs missing
|
||||||
|
# stride information, so this assert will fail.
|
||||||
|
# self.assertEqual(v.strides, ())
|
||||||
|
|
||||||
|
# they are always read/write
|
||||||
|
self.assertFalse(v.readonly)
|
||||||
|
|
||||||
|
if v.shape:
|
||||||
|
n = 1
|
||||||
|
for dim in v.shape:
|
||||||
|
n = n * dim
|
||||||
|
self.assertEqual(n * v.itemsize, len(v.tobytes()))
|
||||||
|
except:
|
||||||
|
# so that we can see the failing type
|
||||||
|
print(tp)
|
||||||
|
raise
|
||||||
|
|
||||||
|
def test_endian_types(self):
|
||||||
|
for tp, fmt, shape, itemtp in endian_types:
|
||||||
|
ob = tp()
|
||||||
|
v = memoryview(ob)
|
||||||
|
try:
|
||||||
|
self.assertEqual(v.format, fmt)
|
||||||
|
if shape:
|
||||||
|
self.assertEqual(len(v), shape[0])
|
||||||
|
else:
|
||||||
|
self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob))
|
||||||
|
self.assertEqual(v.itemsize, sizeof(itemtp))
|
||||||
|
self.assertEqual(v.shape, shape)
|
||||||
|
# XXX Issue #12851
|
||||||
|
# self.assertEqual(v.strides, ())
|
||||||
|
|
||||||
|
# they are always read/write
|
||||||
|
self.assertFalse(v.readonly)
|
||||||
|
|
||||||
|
if v.shape:
|
||||||
|
n = 1
|
||||||
|
for dim in v.shape:
|
||||||
|
n = n * dim
|
||||||
|
self.assertEqual(n, len(v))
|
||||||
|
except:
|
||||||
|
# so that we can see the failing type
|
||||||
|
print(tp)
|
||||||
|
raise
|
||||||
|
|
||||||
|
# define some structure classes
|
||||||
|
|
||||||
|
class Point(Structure):
|
||||||
|
_fields_ = [("x", c_long), ("y", c_long)]
|
||||||
|
|
||||||
|
class PackedPoint(Structure):
|
||||||
|
_pack_ = 2
|
||||||
|
_fields_ = [("x", c_long), ("y", c_long)]
|
||||||
|
|
||||||
|
class Point2(Structure):
|
||||||
|
pass
|
||||||
|
Point2._fields_ = [("x", c_long), ("y", c_long)]
|
||||||
|
|
||||||
|
class EmptyStruct(Structure):
|
||||||
|
_fields_ = []
|
||||||
|
|
||||||
|
class aUnion(Union):
|
||||||
|
_fields_ = [("a", c_int)]
|
||||||
|
|
||||||
|
class StructWithArrays(Structure):
|
||||||
|
_fields_ = [("x", c_long * 3 * 2), ("y", Point * 4)]
|
||||||
|
|
||||||
|
class Incomplete(Structure):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Complete(Structure):
|
||||||
|
pass
|
||||||
|
PComplete = POINTER(Complete)
|
||||||
|
Complete._fields_ = [("a", c_long)]
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
#
|
||||||
|
# This table contains format strings as they look on little endian
|
||||||
|
# machines. The test replaces '<' with '>' on big endian machines.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Platform-specific type codes
|
||||||
|
s_bool = {1: '?', 2: 'H', 4: 'L', 8: 'Q'}[sizeof(c_bool)]
|
||||||
|
s_short = {2: 'h', 4: 'l', 8: 'q'}[sizeof(c_short)]
|
||||||
|
s_ushort = {2: 'H', 4: 'L', 8: 'Q'}[sizeof(c_ushort)]
|
||||||
|
s_int = {2: 'h', 4: 'i', 8: 'q'}[sizeof(c_int)]
|
||||||
|
s_uint = {2: 'H', 4: 'I', 8: 'Q'}[sizeof(c_uint)]
|
||||||
|
s_long = {4: 'l', 8: 'q'}[sizeof(c_long)]
|
||||||
|
s_ulong = {4: 'L', 8: 'Q'}[sizeof(c_ulong)]
|
||||||
|
s_longlong = "q"
|
||||||
|
s_ulonglong = "Q"
|
||||||
|
s_float = "f"
|
||||||
|
s_double = "d"
|
||||||
|
s_longdouble = "g"
|
||||||
|
|
||||||
|
# Alias definitions in ctypes/__init__.py
|
||||||
|
if c_int is c_long:
|
||||||
|
s_int = s_long
|
||||||
|
if c_uint is c_ulong:
|
||||||
|
s_uint = s_ulong
|
||||||
|
if c_longlong is c_long:
|
||||||
|
s_longlong = s_long
|
||||||
|
if c_ulonglong is c_ulong:
|
||||||
|
s_ulonglong = s_ulong
|
||||||
|
if c_longdouble is c_double:
|
||||||
|
s_longdouble = s_double
|
||||||
|
|
||||||
|
|
||||||
|
native_types = [
|
||||||
|
# type format shape calc itemsize
|
||||||
|
|
||||||
|
## simple types
|
||||||
|
|
||||||
|
(c_char, "<c", (), c_char),
|
||||||
|
(c_byte, "<b", (), c_byte),
|
||||||
|
(c_ubyte, "<B", (), c_ubyte),
|
||||||
|
(c_short, "<" + s_short, (), c_short),
|
||||||
|
(c_ushort, "<" + s_ushort, (), c_ushort),
|
||||||
|
|
||||||
|
(c_int, "<" + s_int, (), c_int),
|
||||||
|
(c_uint, "<" + s_uint, (), c_uint),
|
||||||
|
|
||||||
|
(c_long, "<" + s_long, (), c_long),
|
||||||
|
(c_ulong, "<" + s_ulong, (), c_ulong),
|
||||||
|
|
||||||
|
(c_longlong, "<" + s_longlong, (), c_longlong),
|
||||||
|
(c_ulonglong, "<" + s_ulonglong, (), c_ulonglong),
|
||||||
|
|
||||||
|
(c_float, "<f", (), c_float),
|
||||||
|
(c_double, "<d", (), c_double),
|
||||||
|
|
||||||
|
(c_longdouble, "<" + s_longdouble, (), c_longdouble),
|
||||||
|
|
||||||
|
(c_bool, "<" + s_bool, (), c_bool),
|
||||||
|
(py_object, "<O", (), py_object),
|
||||||
|
|
||||||
|
## pointers
|
||||||
|
|
||||||
|
(POINTER(c_byte), "&<b", (), POINTER(c_byte)),
|
||||||
|
(POINTER(POINTER(c_long)), "&&<" + s_long, (), POINTER(POINTER(c_long))),
|
||||||
|
|
||||||
|
## arrays and pointers
|
||||||
|
|
||||||
|
(c_double * 4, "<d", (4,), c_double),
|
||||||
|
(c_double * 0, "<d", (0,), c_double),
|
||||||
|
(c_float * 4 * 3 * 2, "<f", (2,3,4), c_float),
|
||||||
|
(c_float * 4 * 0 * 2, "<f", (2,0,4), c_float),
|
||||||
|
(POINTER(c_short) * 2, "&<" + s_short, (2,), POINTER(c_short)),
|
||||||
|
(POINTER(c_short) * 2 * 3, "&<" + s_short, (3,2,), POINTER(c_short)),
|
||||||
|
(POINTER(c_short * 2), "&(2)<" + s_short, (), POINTER(c_short)),
|
||||||
|
|
||||||
|
## structures and unions
|
||||||
|
|
||||||
|
(Point, "T{<l:x:<l:y:}".replace('l', s_long), (), Point),
|
||||||
|
# packed structures do not implement the pep
|
||||||
|
(PackedPoint, "B", (), PackedPoint),
|
||||||
|
(Point2, "T{<l:x:<l:y:}".replace('l', s_long), (), Point2),
|
||||||
|
(EmptyStruct, "T{}", (), EmptyStruct),
|
||||||
|
# the pep doesn't support unions
|
||||||
|
(aUnion, "B", (), aUnion),
|
||||||
|
# structure with sub-arrays
|
||||||
|
(StructWithArrays, "T{(2,3)<l:x:(4)T{<l:x:<l:y:}:y:}".replace('l', s_long), (), StructWithArrays),
|
||||||
|
(StructWithArrays * 3, "T{(2,3)<l:x:(4)T{<l:x:<l:y:}:y:}".replace('l', s_long), (3,), StructWithArrays),
|
||||||
|
|
||||||
|
## pointer to incomplete structure
|
||||||
|
(Incomplete, "B", (), Incomplete),
|
||||||
|
(POINTER(Incomplete), "&B", (), POINTER(Incomplete)),
|
||||||
|
|
||||||
|
# 'Complete' is a structure that starts incomplete, but is completed after the
|
||||||
|
# pointer type to it has been created.
|
||||||
|
(Complete, "T{<l:a:}".replace('l', s_long), (), Complete),
|
||||||
|
# Unfortunately the pointer format string is not fixed...
|
||||||
|
(POINTER(Complete), "&B", (), POINTER(Complete)),
|
||||||
|
|
||||||
|
## other
|
||||||
|
|
||||||
|
# function signatures are not implemented
|
||||||
|
(CFUNCTYPE(None), "X{}", (), CFUNCTYPE(None)),
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
class BEPoint(BigEndianStructure):
|
||||||
|
_fields_ = [("x", c_long), ("y", c_long)]
|
||||||
|
|
||||||
|
class LEPoint(LittleEndianStructure):
|
||||||
|
_fields_ = [("x", c_long), ("y", c_long)]
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
#
|
||||||
|
# This table contains format strings as they really look, on both big
|
||||||
|
# and little endian machines.
|
||||||
|
#
|
||||||
|
endian_types = [
|
||||||
|
(BEPoint, "T{>l:x:>l:y:}".replace('l', s_long), (), BEPoint),
|
||||||
|
(LEPoint, "T{<l:x:<l:y:}".replace('l', s_long), (), LEPoint),
|
||||||
|
(POINTER(BEPoint), "&T{>l:x:>l:y:}".replace('l', s_long), (), POINTER(BEPoint)),
|
||||||
|
(POINTER(LEPoint), "&T{<l:x:<l:y:}".replace('l', s_long), (), POINTER(LEPoint)),
|
||||||
|
]
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
81
Lib/ctypes/test/test_pickling.py
vendored
Normal file
81
Lib/ctypes/test/test_pickling.py
vendored
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import unittest
|
||||||
|
import pickle
|
||||||
|
from ctypes import *
|
||||||
|
import _ctypes_test
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("a", c_int), ("b", c_double)]
|
||||||
|
init_called = 0
|
||||||
|
def __init__(self, *args, **kw):
|
||||||
|
X.init_called += 1
|
||||||
|
self.x = 42
|
||||||
|
|
||||||
|
class Y(X):
|
||||||
|
_fields_ = [("str", c_char_p)]
|
||||||
|
|
||||||
|
class PickleTest:
|
||||||
|
def dumps(self, item):
|
||||||
|
return pickle.dumps(item, self.proto)
|
||||||
|
|
||||||
|
def loads(self, item):
|
||||||
|
return pickle.loads(item)
|
||||||
|
|
||||||
|
def test_simple(self):
|
||||||
|
for src in [
|
||||||
|
c_int(42),
|
||||||
|
c_double(3.14),
|
||||||
|
]:
|
||||||
|
dst = self.loads(self.dumps(src))
|
||||||
|
self.assertEqual(src.__dict__, dst.__dict__)
|
||||||
|
self.assertEqual(memoryview(src).tobytes(),
|
||||||
|
memoryview(dst).tobytes())
|
||||||
|
|
||||||
|
def test_struct(self):
|
||||||
|
X.init_called = 0
|
||||||
|
|
||||||
|
x = X()
|
||||||
|
x.a = 42
|
||||||
|
self.assertEqual(X.init_called, 1)
|
||||||
|
|
||||||
|
y = self.loads(self.dumps(x))
|
||||||
|
|
||||||
|
# loads must NOT call __init__
|
||||||
|
self.assertEqual(X.init_called, 1)
|
||||||
|
|
||||||
|
# ctypes instances are identical when the instance __dict__
|
||||||
|
# and the memory buffer are identical
|
||||||
|
self.assertEqual(y.__dict__, x.__dict__)
|
||||||
|
self.assertEqual(memoryview(y).tobytes(),
|
||||||
|
memoryview(x).tobytes())
|
||||||
|
|
||||||
|
def test_unpickable(self):
|
||||||
|
# ctypes objects that are pointers or contain pointers are
|
||||||
|
# unpickable.
|
||||||
|
self.assertRaises(ValueError, lambda: self.dumps(Y()))
|
||||||
|
|
||||||
|
prototype = CFUNCTYPE(c_int)
|
||||||
|
|
||||||
|
for item in [
|
||||||
|
c_char_p(),
|
||||||
|
c_wchar_p(),
|
||||||
|
c_void_p(),
|
||||||
|
pointer(c_int(42)),
|
||||||
|
dll._testfunc_p_p,
|
||||||
|
prototype(lambda: 42),
|
||||||
|
]:
|
||||||
|
self.assertRaises(ValueError, lambda: self.dumps(item))
|
||||||
|
|
||||||
|
def test_wchar(self):
|
||||||
|
self.dumps(c_char(b"x"))
|
||||||
|
# Issue 5049
|
||||||
|
self.dumps(c_wchar("x"))
|
||||||
|
|
||||||
|
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
|
||||||
|
name = 'PickleTest_%s' % proto
|
||||||
|
globals()[name] = type(name,
|
||||||
|
(PickleTest, unittest.TestCase),
|
||||||
|
{'proto': proto})
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
223
Lib/ctypes/test/test_pointers.py
vendored
Normal file
223
Lib/ctypes/test/test_pointers.py
vendored
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
import unittest, sys
|
||||||
|
|
||||||
|
from ctypes import *
|
||||||
|
import _ctypes_test
|
||||||
|
|
||||||
|
ctype_types = [c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint,
|
||||||
|
c_long, c_ulong, c_longlong, c_ulonglong, c_double, c_float]
|
||||||
|
python_types = [int, int, int, int, int, int,
|
||||||
|
int, int, int, int, float, float]
|
||||||
|
|
||||||
|
class PointersTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_pointer_crash(self):
|
||||||
|
|
||||||
|
class A(POINTER(c_ulong)):
|
||||||
|
pass
|
||||||
|
|
||||||
|
POINTER(c_ulong)(c_ulong(22))
|
||||||
|
# Pointer can't set contents: has no _type_
|
||||||
|
self.assertRaises(TypeError, A, c_ulong(33))
|
||||||
|
|
||||||
|
def test_pass_pointers(self):
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
func = dll._testfunc_p_p
|
||||||
|
if sizeof(c_longlong) == sizeof(c_void_p):
|
||||||
|
func.restype = c_longlong
|
||||||
|
else:
|
||||||
|
func.restype = c_long
|
||||||
|
|
||||||
|
i = c_int(12345678)
|
||||||
|
## func.argtypes = (POINTER(c_int),)
|
||||||
|
address = func(byref(i))
|
||||||
|
self.assertEqual(c_int.from_address(address).value, 12345678)
|
||||||
|
|
||||||
|
func.restype = POINTER(c_int)
|
||||||
|
res = func(pointer(i))
|
||||||
|
self.assertEqual(res.contents.value, 12345678)
|
||||||
|
self.assertEqual(res[0], 12345678)
|
||||||
|
|
||||||
|
def test_change_pointers(self):
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
func = dll._testfunc_p_p
|
||||||
|
|
||||||
|
i = c_int(87654)
|
||||||
|
func.restype = POINTER(c_int)
|
||||||
|
func.argtypes = (POINTER(c_int),)
|
||||||
|
|
||||||
|
res = func(pointer(i))
|
||||||
|
self.assertEqual(res[0], 87654)
|
||||||
|
self.assertEqual(res.contents.value, 87654)
|
||||||
|
|
||||||
|
# C code: *res = 54345
|
||||||
|
res[0] = 54345
|
||||||
|
self.assertEqual(i.value, 54345)
|
||||||
|
|
||||||
|
# C code:
|
||||||
|
# int x = 12321;
|
||||||
|
# res = &x
|
||||||
|
x = c_int(12321)
|
||||||
|
res.contents = x
|
||||||
|
self.assertEqual(i.value, 54345)
|
||||||
|
|
||||||
|
x.value = -99
|
||||||
|
self.assertEqual(res.contents.value, -99)
|
||||||
|
|
||||||
|
def test_callbacks_with_pointers(self):
|
||||||
|
# a function type receiving a pointer
|
||||||
|
PROTOTYPE = CFUNCTYPE(c_int, POINTER(c_int))
|
||||||
|
|
||||||
|
self.result = []
|
||||||
|
|
||||||
|
def func(arg):
|
||||||
|
for i in range(10):
|
||||||
|
## print arg[i],
|
||||||
|
self.result.append(arg[i])
|
||||||
|
## print
|
||||||
|
return 0
|
||||||
|
callback = PROTOTYPE(func)
|
||||||
|
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
# This function expects a function pointer,
|
||||||
|
# and calls this with an integer pointer as parameter.
|
||||||
|
# The int pointer points to a table containing the numbers 1..10
|
||||||
|
doit = dll._testfunc_callback_with_pointer
|
||||||
|
|
||||||
|
## i = c_int(42)
|
||||||
|
## callback(byref(i))
|
||||||
|
## self.assertEqual(i.value, 84)
|
||||||
|
|
||||||
|
doit(callback)
|
||||||
|
## print self.result
|
||||||
|
doit(callback)
|
||||||
|
## print self.result
|
||||||
|
|
||||||
|
def test_basics(self):
|
||||||
|
from operator import delitem
|
||||||
|
for ct, pt in zip(ctype_types, python_types):
|
||||||
|
i = ct(42)
|
||||||
|
p = pointer(i)
|
||||||
|
## print type(p.contents), ct
|
||||||
|
self.assertIs(type(p.contents), ct)
|
||||||
|
# p.contents is the same as p[0]
|
||||||
|
## print p.contents
|
||||||
|
## self.assertEqual(p.contents, 42)
|
||||||
|
## self.assertEqual(p[0], 42)
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, delitem, p, 0)
|
||||||
|
|
||||||
|
def test_from_address(self):
|
||||||
|
from array import array
|
||||||
|
a = array('i', [100, 200, 300, 400, 500])
|
||||||
|
addr = a.buffer_info()[0]
|
||||||
|
|
||||||
|
p = POINTER(POINTER(c_int))
|
||||||
|
## print dir(p)
|
||||||
|
## print p.from_address
|
||||||
|
## print p.from_address(addr)[0][0]
|
||||||
|
|
||||||
|
def test_other(self):
|
||||||
|
class Table(Structure):
|
||||||
|
_fields_ = [("a", c_int),
|
||||||
|
("b", c_int),
|
||||||
|
("c", c_int)]
|
||||||
|
|
||||||
|
pt = pointer(Table(1, 2, 3))
|
||||||
|
|
||||||
|
self.assertEqual(pt.contents.a, 1)
|
||||||
|
self.assertEqual(pt.contents.b, 2)
|
||||||
|
self.assertEqual(pt.contents.c, 3)
|
||||||
|
|
||||||
|
pt.contents.c = 33
|
||||||
|
|
||||||
|
from ctypes import _pointer_type_cache
|
||||||
|
del _pointer_type_cache[Table]
|
||||||
|
|
||||||
|
def test_basic(self):
|
||||||
|
p = pointer(c_int(42))
|
||||||
|
# Although a pointer can be indexed, it has no length
|
||||||
|
self.assertRaises(TypeError, len, p)
|
||||||
|
self.assertEqual(p[0], 42)
|
||||||
|
self.assertEqual(p[0:1], [42])
|
||||||
|
self.assertEqual(p.contents.value, 42)
|
||||||
|
|
||||||
|
def test_charpp(self):
|
||||||
|
"""Test that a character pointer-to-pointer is correctly passed"""
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
func = dll._testfunc_c_p_p
|
||||||
|
func.restype = c_char_p
|
||||||
|
argv = (c_char_p * 2)()
|
||||||
|
argc = c_int( 2 )
|
||||||
|
argv[0] = b'hello'
|
||||||
|
argv[1] = b'world'
|
||||||
|
result = func( byref(argc), argv )
|
||||||
|
self.assertEqual(result, b'world')
|
||||||
|
|
||||||
|
def test_bug_1467852(self):
|
||||||
|
# http://sourceforge.net/tracker/?func=detail&atid=532154&aid=1467852&group_id=71702
|
||||||
|
x = c_int(5)
|
||||||
|
dummy = []
|
||||||
|
for i in range(32000):
|
||||||
|
dummy.append(c_int(i))
|
||||||
|
y = c_int(6)
|
||||||
|
p = pointer(x)
|
||||||
|
pp = pointer(p)
|
||||||
|
q = pointer(y)
|
||||||
|
pp[0] = q # <==
|
||||||
|
self.assertEqual(p[0], 6)
|
||||||
|
def test_c_void_p(self):
|
||||||
|
# http://sourceforge.net/tracker/?func=detail&aid=1518190&group_id=5470&atid=105470
|
||||||
|
if sizeof(c_void_p) == 4:
|
||||||
|
self.assertEqual(c_void_p(0xFFFFFFFF).value,
|
||||||
|
c_void_p(-1).value)
|
||||||
|
self.assertEqual(c_void_p(0xFFFFFFFFFFFFFFFF).value,
|
||||||
|
c_void_p(-1).value)
|
||||||
|
elif sizeof(c_void_p) == 8:
|
||||||
|
self.assertEqual(c_void_p(0xFFFFFFFF).value,
|
||||||
|
0xFFFFFFFF)
|
||||||
|
self.assertEqual(c_void_p(0xFFFFFFFFFFFFFFFF).value,
|
||||||
|
c_void_p(-1).value)
|
||||||
|
self.assertEqual(c_void_p(0xFFFFFFFFFFFFFFFFFFFFFFFF).value,
|
||||||
|
c_void_p(-1).value)
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, c_void_p, 3.14) # make sure floats are NOT accepted
|
||||||
|
self.assertRaises(TypeError, c_void_p, object()) # nor other objects
|
||||||
|
|
||||||
|
def test_pointers_bool(self):
|
||||||
|
# NULL pointers have a boolean False value, non-NULL pointers True.
|
||||||
|
self.assertEqual(bool(POINTER(c_int)()), False)
|
||||||
|
self.assertEqual(bool(pointer(c_int())), True)
|
||||||
|
|
||||||
|
self.assertEqual(bool(CFUNCTYPE(None)(0)), False)
|
||||||
|
self.assertEqual(bool(CFUNCTYPE(None)(42)), True)
|
||||||
|
|
||||||
|
# COM methods are boolean True:
|
||||||
|
if sys.platform == "win32":
|
||||||
|
mth = WINFUNCTYPE(None)(42, "name", (), None)
|
||||||
|
self.assertEqual(bool(mth), True)
|
||||||
|
|
||||||
|
def test_pointer_type_name(self):
|
||||||
|
LargeNamedType = type('T' * 2 ** 25, (Structure,), {})
|
||||||
|
self.assertTrue(POINTER(LargeNamedType))
|
||||||
|
|
||||||
|
# to not leak references, we must clean _pointer_type_cache
|
||||||
|
from ctypes import _pointer_type_cache
|
||||||
|
del _pointer_type_cache[LargeNamedType]
|
||||||
|
|
||||||
|
def test_pointer_type_str_name(self):
|
||||||
|
large_string = 'T' * 2 ** 25
|
||||||
|
P = POINTER(large_string)
|
||||||
|
self.assertTrue(P)
|
||||||
|
|
||||||
|
# to not leak references, we must clean _pointer_type_cache
|
||||||
|
from ctypes import _pointer_type_cache
|
||||||
|
del _pointer_type_cache[id(P)]
|
||||||
|
|
||||||
|
def test_abstract(self):
|
||||||
|
from ctypes import _Pointer
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, _Pointer.set_type, 42)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
222
Lib/ctypes/test/test_prototypes.py
vendored
Normal file
222
Lib/ctypes/test/test_prototypes.py
vendored
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
from ctypes import *
|
||||||
|
from ctypes.test import need_symbol
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
# IMPORTANT INFO:
|
||||||
|
#
|
||||||
|
# Consider this call:
|
||||||
|
# func.restype = c_char_p
|
||||||
|
# func(c_char_p("123"))
|
||||||
|
# It returns
|
||||||
|
# "123"
|
||||||
|
#
|
||||||
|
# WHY IS THIS SO?
|
||||||
|
#
|
||||||
|
# argument tuple (c_char_p("123"), ) is destroyed after the function
|
||||||
|
# func is called, but NOT before the result is actually built.
|
||||||
|
#
|
||||||
|
# If the arglist would be destroyed BEFORE the result has been built,
|
||||||
|
# the c_char_p("123") object would already have a zero refcount,
|
||||||
|
# and the pointer passed to (and returned by) the function would
|
||||||
|
# probably point to deallocated space.
|
||||||
|
#
|
||||||
|
# In this case, there would have to be an additional reference to the argument...
|
||||||
|
|
||||||
|
import _ctypes_test
|
||||||
|
testdll = CDLL(_ctypes_test.__file__)
|
||||||
|
|
||||||
|
# Return machine address `a` as a (possibly long) non-negative integer.
|
||||||
|
# Starting with Python 2.5, id(anything) is always non-negative, and
|
||||||
|
# the ctypes addressof() inherits that via PyLong_FromVoidPtr().
|
||||||
|
def positive_address(a):
|
||||||
|
if a >= 0:
|
||||||
|
return a
|
||||||
|
# View the bits in `a` as unsigned instead.
|
||||||
|
import struct
|
||||||
|
num_bits = struct.calcsize("P") * 8 # num bits in native machine address
|
||||||
|
a += 1 << num_bits
|
||||||
|
assert a >= 0
|
||||||
|
return a
|
||||||
|
|
||||||
|
def c_wbuffer(init):
|
||||||
|
n = len(init) + 1
|
||||||
|
return (c_wchar * n)(*init)
|
||||||
|
|
||||||
|
class CharPointersTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
func = testdll._testfunc_p_p
|
||||||
|
func.restype = c_long
|
||||||
|
func.argtypes = None
|
||||||
|
|
||||||
|
def test_paramflags(self):
|
||||||
|
# function returns c_void_p result,
|
||||||
|
# and has a required parameter named 'input'
|
||||||
|
prototype = CFUNCTYPE(c_void_p, c_void_p)
|
||||||
|
func = prototype(("_testfunc_p_p", testdll),
|
||||||
|
((1, "input"),))
|
||||||
|
|
||||||
|
try:
|
||||||
|
func()
|
||||||
|
except TypeError as details:
|
||||||
|
self.assertEqual(str(details), "required argument 'input' missing")
|
||||||
|
else:
|
||||||
|
self.fail("TypeError not raised")
|
||||||
|
|
||||||
|
self.assertEqual(func(None), None)
|
||||||
|
self.assertEqual(func(input=None), None)
|
||||||
|
|
||||||
|
|
||||||
|
def test_int_pointer_arg(self):
|
||||||
|
func = testdll._testfunc_p_p
|
||||||
|
if sizeof(c_longlong) == sizeof(c_void_p):
|
||||||
|
func.restype = c_longlong
|
||||||
|
else:
|
||||||
|
func.restype = c_long
|
||||||
|
self.assertEqual(0, func(0))
|
||||||
|
|
||||||
|
ci = c_int(0)
|
||||||
|
|
||||||
|
func.argtypes = POINTER(c_int),
|
||||||
|
self.assertEqual(positive_address(addressof(ci)),
|
||||||
|
positive_address(func(byref(ci))))
|
||||||
|
|
||||||
|
func.argtypes = c_char_p,
|
||||||
|
self.assertRaises(ArgumentError, func, byref(ci))
|
||||||
|
|
||||||
|
func.argtypes = POINTER(c_short),
|
||||||
|
self.assertRaises(ArgumentError, func, byref(ci))
|
||||||
|
|
||||||
|
func.argtypes = POINTER(c_double),
|
||||||
|
self.assertRaises(ArgumentError, func, byref(ci))
|
||||||
|
|
||||||
|
def test_POINTER_c_char_arg(self):
|
||||||
|
func = testdll._testfunc_p_p
|
||||||
|
func.restype = c_char_p
|
||||||
|
func.argtypes = POINTER(c_char),
|
||||||
|
|
||||||
|
self.assertEqual(None, func(None))
|
||||||
|
self.assertEqual(b"123", func(b"123"))
|
||||||
|
self.assertEqual(None, func(c_char_p(None)))
|
||||||
|
self.assertEqual(b"123", func(c_char_p(b"123")))
|
||||||
|
|
||||||
|
self.assertEqual(b"123", func(c_buffer(b"123")))
|
||||||
|
ca = c_char(b"a")
|
||||||
|
self.assertEqual(ord(b"a"), func(pointer(ca))[0])
|
||||||
|
self.assertEqual(ord(b"a"), func(byref(ca))[0])
|
||||||
|
|
||||||
|
def test_c_char_p_arg(self):
|
||||||
|
func = testdll._testfunc_p_p
|
||||||
|
func.restype = c_char_p
|
||||||
|
func.argtypes = c_char_p,
|
||||||
|
|
||||||
|
self.assertEqual(None, func(None))
|
||||||
|
self.assertEqual(b"123", func(b"123"))
|
||||||
|
self.assertEqual(None, func(c_char_p(None)))
|
||||||
|
self.assertEqual(b"123", func(c_char_p(b"123")))
|
||||||
|
|
||||||
|
self.assertEqual(b"123", func(c_buffer(b"123")))
|
||||||
|
ca = c_char(b"a")
|
||||||
|
self.assertEqual(ord(b"a"), func(pointer(ca))[0])
|
||||||
|
self.assertEqual(ord(b"a"), func(byref(ca))[0])
|
||||||
|
|
||||||
|
def test_c_void_p_arg(self):
|
||||||
|
func = testdll._testfunc_p_p
|
||||||
|
func.restype = c_char_p
|
||||||
|
func.argtypes = c_void_p,
|
||||||
|
|
||||||
|
self.assertEqual(None, func(None))
|
||||||
|
self.assertEqual(b"123", func(b"123"))
|
||||||
|
self.assertEqual(b"123", func(c_char_p(b"123")))
|
||||||
|
self.assertEqual(None, func(c_char_p(None)))
|
||||||
|
|
||||||
|
self.assertEqual(b"123", func(c_buffer(b"123")))
|
||||||
|
ca = c_char(b"a")
|
||||||
|
self.assertEqual(ord(b"a"), func(pointer(ca))[0])
|
||||||
|
self.assertEqual(ord(b"a"), func(byref(ca))[0])
|
||||||
|
|
||||||
|
func(byref(c_int()))
|
||||||
|
func(pointer(c_int()))
|
||||||
|
func((c_int * 3)())
|
||||||
|
|
||||||
|
@need_symbol('c_wchar_p')
|
||||||
|
def test_c_void_p_arg_with_c_wchar_p(self):
|
||||||
|
func = testdll._testfunc_p_p
|
||||||
|
func.restype = c_wchar_p
|
||||||
|
func.argtypes = c_void_p,
|
||||||
|
|
||||||
|
self.assertEqual(None, func(c_wchar_p(None)))
|
||||||
|
self.assertEqual("123", func(c_wchar_p("123")))
|
||||||
|
|
||||||
|
def test_instance(self):
|
||||||
|
func = testdll._testfunc_p_p
|
||||||
|
func.restype = c_void_p
|
||||||
|
|
||||||
|
class X:
|
||||||
|
_as_parameter_ = None
|
||||||
|
|
||||||
|
func.argtypes = c_void_p,
|
||||||
|
self.assertEqual(None, func(X()))
|
||||||
|
|
||||||
|
func.argtypes = None
|
||||||
|
self.assertEqual(None, func(X()))
|
||||||
|
|
||||||
|
@need_symbol('c_wchar')
|
||||||
|
class WCharPointersTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
func = testdll._testfunc_p_p
|
||||||
|
func.restype = c_int
|
||||||
|
func.argtypes = None
|
||||||
|
|
||||||
|
|
||||||
|
def test_POINTER_c_wchar_arg(self):
|
||||||
|
func = testdll._testfunc_p_p
|
||||||
|
func.restype = c_wchar_p
|
||||||
|
func.argtypes = POINTER(c_wchar),
|
||||||
|
|
||||||
|
self.assertEqual(None, func(None))
|
||||||
|
self.assertEqual("123", func("123"))
|
||||||
|
self.assertEqual(None, func(c_wchar_p(None)))
|
||||||
|
self.assertEqual("123", func(c_wchar_p("123")))
|
||||||
|
|
||||||
|
self.assertEqual("123", func(c_wbuffer("123")))
|
||||||
|
ca = c_wchar("a")
|
||||||
|
self.assertEqual("a", func(pointer(ca))[0])
|
||||||
|
self.assertEqual("a", func(byref(ca))[0])
|
||||||
|
|
||||||
|
def test_c_wchar_p_arg(self):
|
||||||
|
func = testdll._testfunc_p_p
|
||||||
|
func.restype = c_wchar_p
|
||||||
|
func.argtypes = c_wchar_p,
|
||||||
|
|
||||||
|
c_wchar_p.from_param("123")
|
||||||
|
|
||||||
|
self.assertEqual(None, func(None))
|
||||||
|
self.assertEqual("123", func("123"))
|
||||||
|
self.assertEqual(None, func(c_wchar_p(None)))
|
||||||
|
self.assertEqual("123", func(c_wchar_p("123")))
|
||||||
|
|
||||||
|
# XXX Currently, these raise TypeErrors, although they shouldn't:
|
||||||
|
self.assertEqual("123", func(c_wbuffer("123")))
|
||||||
|
ca = c_wchar("a")
|
||||||
|
self.assertEqual("a", func(pointer(ca))[0])
|
||||||
|
self.assertEqual("a", func(byref(ca))[0])
|
||||||
|
|
||||||
|
class ArrayTest(unittest.TestCase):
|
||||||
|
def test(self):
|
||||||
|
func = testdll._testfunc_ai8
|
||||||
|
func.restype = POINTER(c_int)
|
||||||
|
func.argtypes = c_int * 8,
|
||||||
|
|
||||||
|
func((c_int * 8)(1, 2, 3, 4, 5, 6, 7, 8))
|
||||||
|
|
||||||
|
# This did crash before:
|
||||||
|
|
||||||
|
def func(): pass
|
||||||
|
CFUNCTYPE(None, c_int * 3)(func)
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
85
Lib/ctypes/test/test_python_api.py
vendored
Normal file
85
Lib/ctypes/test/test_python_api.py
vendored
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
from ctypes import *
|
||||||
|
import unittest
|
||||||
|
from test import support
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# This section should be moved into ctypes\__init__.py, when it's ready.
|
||||||
|
|
||||||
|
from _ctypes import PyObj_FromPtr
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
from sys import getrefcount as grc
|
||||||
|
|
||||||
|
class PythonAPITestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_PyBytes_FromStringAndSize(self):
|
||||||
|
PyBytes_FromStringAndSize = pythonapi.PyBytes_FromStringAndSize
|
||||||
|
|
||||||
|
PyBytes_FromStringAndSize.restype = py_object
|
||||||
|
PyBytes_FromStringAndSize.argtypes = c_char_p, c_size_t
|
||||||
|
|
||||||
|
self.assertEqual(PyBytes_FromStringAndSize(b"abcdefghi", 3), b"abc")
|
||||||
|
|
||||||
|
@support.refcount_test
|
||||||
|
def test_PyString_FromString(self):
|
||||||
|
pythonapi.PyBytes_FromString.restype = py_object
|
||||||
|
pythonapi.PyBytes_FromString.argtypes = (c_char_p,)
|
||||||
|
|
||||||
|
s = b"abc"
|
||||||
|
refcnt = grc(s)
|
||||||
|
pyob = pythonapi.PyBytes_FromString(s)
|
||||||
|
self.assertEqual(grc(s), refcnt)
|
||||||
|
self.assertEqual(s, pyob)
|
||||||
|
del pyob
|
||||||
|
self.assertEqual(grc(s), refcnt)
|
||||||
|
|
||||||
|
@support.refcount_test
|
||||||
|
def test_PyLong_Long(self):
|
||||||
|
ref42 = grc(42)
|
||||||
|
pythonapi.PyLong_FromLong.restype = py_object
|
||||||
|
self.assertEqual(pythonapi.PyLong_FromLong(42), 42)
|
||||||
|
|
||||||
|
self.assertEqual(grc(42), ref42)
|
||||||
|
|
||||||
|
pythonapi.PyLong_AsLong.argtypes = (py_object,)
|
||||||
|
pythonapi.PyLong_AsLong.restype = c_long
|
||||||
|
|
||||||
|
res = pythonapi.PyLong_AsLong(42)
|
||||||
|
self.assertEqual(grc(res), ref42 + 1)
|
||||||
|
del res
|
||||||
|
self.assertEqual(grc(42), ref42)
|
||||||
|
|
||||||
|
@support.refcount_test
|
||||||
|
def test_PyObj_FromPtr(self):
|
||||||
|
s = "abc def ghi jkl"
|
||||||
|
ref = grc(s)
|
||||||
|
# id(python-object) is the address
|
||||||
|
pyobj = PyObj_FromPtr(id(s))
|
||||||
|
self.assertIs(s, pyobj)
|
||||||
|
|
||||||
|
self.assertEqual(grc(s), ref + 1)
|
||||||
|
del pyobj
|
||||||
|
self.assertEqual(grc(s), ref)
|
||||||
|
|
||||||
|
def test_PyOS_snprintf(self):
|
||||||
|
PyOS_snprintf = pythonapi.PyOS_snprintf
|
||||||
|
PyOS_snprintf.argtypes = POINTER(c_char), c_size_t, c_char_p
|
||||||
|
|
||||||
|
buf = c_buffer(256)
|
||||||
|
PyOS_snprintf(buf, sizeof(buf), b"Hello from %s", b"ctypes")
|
||||||
|
self.assertEqual(buf.value, b"Hello from ctypes")
|
||||||
|
|
||||||
|
PyOS_snprintf(buf, sizeof(buf), b"Hello from %s (%d, %d, %d)", b"ctypes", 1, 2, 3)
|
||||||
|
self.assertEqual(buf.value, b"Hello from ctypes (1, 2, 3)")
|
||||||
|
|
||||||
|
# not enough arguments
|
||||||
|
self.assertRaises(TypeError, PyOS_snprintf, buf)
|
||||||
|
|
||||||
|
def test_pyobject_repr(self):
|
||||||
|
self.assertEqual(repr(py_object()), "py_object(<NULL>)")
|
||||||
|
self.assertEqual(repr(py_object(42)), "py_object(42)")
|
||||||
|
self.assertEqual(repr(py_object(object)), "py_object(%r)" % object)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
77
Lib/ctypes/test/test_random_things.py
vendored
Normal file
77
Lib/ctypes/test/test_random_things.py
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
from ctypes import *
|
||||||
|
import contextlib
|
||||||
|
from test import support
|
||||||
|
import unittest
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def callback_func(arg):
|
||||||
|
42 / arg
|
||||||
|
raise ValueError(arg)
|
||||||
|
|
||||||
|
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
|
||||||
|
class call_function_TestCase(unittest.TestCase):
|
||||||
|
# _ctypes.call_function is deprecated and private, but used by
|
||||||
|
# Gary Bishp's readline module. If we have it, we must test it as well.
|
||||||
|
|
||||||
|
def test(self):
|
||||||
|
from _ctypes import call_function
|
||||||
|
windll.kernel32.LoadLibraryA.restype = c_void_p
|
||||||
|
windll.kernel32.GetProcAddress.argtypes = c_void_p, c_char_p
|
||||||
|
windll.kernel32.GetProcAddress.restype = c_void_p
|
||||||
|
|
||||||
|
hdll = windll.kernel32.LoadLibraryA(b"kernel32")
|
||||||
|
funcaddr = windll.kernel32.GetProcAddress(hdll, b"GetModuleHandleA")
|
||||||
|
|
||||||
|
self.assertEqual(call_function(funcaddr, (None,)),
|
||||||
|
windll.kernel32.GetModuleHandleA(None))
|
||||||
|
|
||||||
|
class CallbackTracbackTestCase(unittest.TestCase):
|
||||||
|
# When an exception is raised in a ctypes callback function, the C
|
||||||
|
# code prints a traceback.
|
||||||
|
#
|
||||||
|
# This test makes sure the exception types *and* the exception
|
||||||
|
# value is printed correctly.
|
||||||
|
#
|
||||||
|
# Changed in 0.9.3: No longer is '(in callback)' prepended to the
|
||||||
|
# error message - instead an additional frame for the C code is
|
||||||
|
# created, then a full traceback printed. When SystemExit is
|
||||||
|
# raised in a callback function, the interpreter exits.
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def expect_unraisable(self, exc_type, exc_msg=None):
|
||||||
|
with support.catch_unraisable_exception() as cm:
|
||||||
|
yield
|
||||||
|
|
||||||
|
self.assertIsInstance(cm.unraisable.exc_value, exc_type)
|
||||||
|
if exc_msg is not None:
|
||||||
|
self.assertEqual(str(cm.unraisable.exc_value), exc_msg)
|
||||||
|
self.assertEqual(cm.unraisable.err_msg,
|
||||||
|
"Exception ignored on calling ctypes "
|
||||||
|
"callback function")
|
||||||
|
self.assertIs(cm.unraisable.object, callback_func)
|
||||||
|
|
||||||
|
def test_ValueError(self):
|
||||||
|
cb = CFUNCTYPE(c_int, c_int)(callback_func)
|
||||||
|
with self.expect_unraisable(ValueError, '42'):
|
||||||
|
cb(42)
|
||||||
|
|
||||||
|
def test_IntegerDivisionError(self):
|
||||||
|
cb = CFUNCTYPE(c_int, c_int)(callback_func)
|
||||||
|
with self.expect_unraisable(ZeroDivisionError):
|
||||||
|
cb(0)
|
||||||
|
|
||||||
|
def test_FloatDivisionError(self):
|
||||||
|
cb = CFUNCTYPE(c_int, c_double)(callback_func)
|
||||||
|
with self.expect_unraisable(ZeroDivisionError):
|
||||||
|
cb(0.0)
|
||||||
|
|
||||||
|
def test_TypeErrorDivisionError(self):
|
||||||
|
cb = CFUNCTYPE(c_int, c_char_p)(callback_func)
|
||||||
|
err_msg = "unsupported operand type(s) for /: 'int' and 'bytes'"
|
||||||
|
with self.expect_unraisable(TypeError, err_msg):
|
||||||
|
cb(b"spam")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
116
Lib/ctypes/test/test_refcounts.py
vendored
Normal file
116
Lib/ctypes/test/test_refcounts.py
vendored
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
import unittest
|
||||||
|
from test import support
|
||||||
|
import ctypes
|
||||||
|
import gc
|
||||||
|
|
||||||
|
MyCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)
|
||||||
|
OtherCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_ulonglong)
|
||||||
|
|
||||||
|
import _ctypes_test
|
||||||
|
dll = ctypes.CDLL(_ctypes_test.__file__)
|
||||||
|
|
||||||
|
class RefcountTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
@support.refcount_test
|
||||||
|
def test_1(self):
|
||||||
|
from sys import getrefcount as grc
|
||||||
|
|
||||||
|
f = dll._testfunc_callback_i_if
|
||||||
|
f.restype = ctypes.c_int
|
||||||
|
f.argtypes = [ctypes.c_int, MyCallback]
|
||||||
|
|
||||||
|
def callback(value):
|
||||||
|
#print "called back with", value
|
||||||
|
return value
|
||||||
|
|
||||||
|
self.assertEqual(grc(callback), 2)
|
||||||
|
cb = MyCallback(callback)
|
||||||
|
|
||||||
|
self.assertGreater(grc(callback), 2)
|
||||||
|
result = f(-10, cb)
|
||||||
|
self.assertEqual(result, -18)
|
||||||
|
cb = None
|
||||||
|
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
|
self.assertEqual(grc(callback), 2)
|
||||||
|
|
||||||
|
|
||||||
|
@support.refcount_test
|
||||||
|
def test_refcount(self):
|
||||||
|
from sys import getrefcount as grc
|
||||||
|
def func(*args):
|
||||||
|
pass
|
||||||
|
# this is the standard refcount for func
|
||||||
|
self.assertEqual(grc(func), 2)
|
||||||
|
|
||||||
|
# the CFuncPtr instance holds at least one refcount on func:
|
||||||
|
f = OtherCallback(func)
|
||||||
|
self.assertGreater(grc(func), 2)
|
||||||
|
|
||||||
|
# and may release it again
|
||||||
|
del f
|
||||||
|
self.assertGreaterEqual(grc(func), 2)
|
||||||
|
|
||||||
|
# but now it must be gone
|
||||||
|
gc.collect()
|
||||||
|
self.assertEqual(grc(func), 2)
|
||||||
|
|
||||||
|
class X(ctypes.Structure):
|
||||||
|
_fields_ = [("a", OtherCallback)]
|
||||||
|
x = X()
|
||||||
|
x.a = OtherCallback(func)
|
||||||
|
|
||||||
|
# the CFuncPtr instance holds at least one refcount on func:
|
||||||
|
self.assertGreater(grc(func), 2)
|
||||||
|
|
||||||
|
# and may release it again
|
||||||
|
del x
|
||||||
|
self.assertGreaterEqual(grc(func), 2)
|
||||||
|
|
||||||
|
# and now it must be gone again
|
||||||
|
gc.collect()
|
||||||
|
self.assertEqual(grc(func), 2)
|
||||||
|
|
||||||
|
f = OtherCallback(func)
|
||||||
|
|
||||||
|
# the CFuncPtr instance holds at least one refcount on func:
|
||||||
|
self.assertGreater(grc(func), 2)
|
||||||
|
|
||||||
|
# create a cycle
|
||||||
|
f.cycle = f
|
||||||
|
|
||||||
|
del f
|
||||||
|
gc.collect()
|
||||||
|
self.assertEqual(grc(func), 2)
|
||||||
|
|
||||||
|
class AnotherLeak(unittest.TestCase):
|
||||||
|
def test_callback(self):
|
||||||
|
import sys
|
||||||
|
|
||||||
|
proto = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_int)
|
||||||
|
def func(a, b):
|
||||||
|
return a * b * 2
|
||||||
|
f = proto(func)
|
||||||
|
|
||||||
|
a = sys.getrefcount(ctypes.c_int)
|
||||||
|
f(1, 2)
|
||||||
|
self.assertEqual(sys.getrefcount(ctypes.c_int), a)
|
||||||
|
|
||||||
|
@support.refcount_test
|
||||||
|
def test_callback_py_object_none_return(self):
|
||||||
|
# bpo-36880: test that returning None from a py_object callback
|
||||||
|
# does not decrement the refcount of None.
|
||||||
|
|
||||||
|
for FUNCTYPE in (ctypes.CFUNCTYPE, ctypes.PYFUNCTYPE):
|
||||||
|
with self.subTest(FUNCTYPE=FUNCTYPE):
|
||||||
|
@FUNCTYPE(ctypes.py_object)
|
||||||
|
def func():
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Check that calling func does not affect None's refcount.
|
||||||
|
for _ in range(10000):
|
||||||
|
func()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
29
Lib/ctypes/test/test_repr.py
vendored
Normal file
29
Lib/ctypes/test/test_repr.py
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
from ctypes import *
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
subclasses = []
|
||||||
|
for base in [c_byte, c_short, c_int, c_long, c_longlong,
|
||||||
|
c_ubyte, c_ushort, c_uint, c_ulong, c_ulonglong,
|
||||||
|
c_float, c_double, c_longdouble, c_bool]:
|
||||||
|
class X(base):
|
||||||
|
pass
|
||||||
|
subclasses.append(X)
|
||||||
|
|
||||||
|
class X(c_char):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# This test checks if the __repr__ is correct for subclasses of simple types
|
||||||
|
|
||||||
|
class ReprTest(unittest.TestCase):
|
||||||
|
def test_numbers(self):
|
||||||
|
for typ in subclasses:
|
||||||
|
base = typ.__bases__[0]
|
||||||
|
self.assertTrue(repr(base(42)).startswith(base.__name__))
|
||||||
|
self.assertEqual("<X object at", repr(typ(42))[:12])
|
||||||
|
|
||||||
|
def test_char(self):
|
||||||
|
self.assertEqual("c_char(b'x')", repr(c_char(b'x')))
|
||||||
|
self.assertEqual("<X object at", repr(X(b'x'))[:12])
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
66
Lib/ctypes/test/test_returnfuncptrs.py
vendored
Normal file
66
Lib/ctypes/test/test_returnfuncptrs.py
vendored
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import unittest
|
||||||
|
from ctypes import *
|
||||||
|
|
||||||
|
import _ctypes_test
|
||||||
|
|
||||||
|
class ReturnFuncPtrTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_with_prototype(self):
|
||||||
|
# The _ctypes_test shared lib/dll exports quite some functions for testing.
|
||||||
|
# The get_strchr function returns a *pointer* to the C strchr function.
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
get_strchr = dll.get_strchr
|
||||||
|
get_strchr.restype = CFUNCTYPE(c_char_p, c_char_p, c_char)
|
||||||
|
strchr = get_strchr()
|
||||||
|
self.assertEqual(strchr(b"abcdef", b"b"), b"bcdef")
|
||||||
|
self.assertEqual(strchr(b"abcdef", b"x"), None)
|
||||||
|
self.assertEqual(strchr(b"abcdef", 98), b"bcdef")
|
||||||
|
self.assertEqual(strchr(b"abcdef", 107), None)
|
||||||
|
self.assertRaises(ArgumentError, strchr, b"abcdef", 3.0)
|
||||||
|
self.assertRaises(TypeError, strchr, b"abcdef")
|
||||||
|
|
||||||
|
def test_without_prototype(self):
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
get_strchr = dll.get_strchr
|
||||||
|
# the default 'c_int' would not work on systems where sizeof(int) != sizeof(void *)
|
||||||
|
get_strchr.restype = c_void_p
|
||||||
|
addr = get_strchr()
|
||||||
|
# _CFuncPtr instances are now callable with an integer argument
|
||||||
|
# which denotes a function address:
|
||||||
|
strchr = CFUNCTYPE(c_char_p, c_char_p, c_char)(addr)
|
||||||
|
self.assertTrue(strchr(b"abcdef", b"b"), "bcdef")
|
||||||
|
self.assertEqual(strchr(b"abcdef", b"x"), None)
|
||||||
|
self.assertRaises(ArgumentError, strchr, b"abcdef", 3.0)
|
||||||
|
self.assertRaises(TypeError, strchr, b"abcdef")
|
||||||
|
|
||||||
|
def test_from_dll(self):
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
# _CFuncPtr instances are now callable with a tuple argument
|
||||||
|
# which denotes a function name and a dll:
|
||||||
|
strchr = CFUNCTYPE(c_char_p, c_char_p, c_char)(("my_strchr", dll))
|
||||||
|
self.assertTrue(strchr(b"abcdef", b"b"), "bcdef")
|
||||||
|
self.assertEqual(strchr(b"abcdef", b"x"), None)
|
||||||
|
self.assertRaises(ArgumentError, strchr, b"abcdef", 3.0)
|
||||||
|
self.assertRaises(TypeError, strchr, b"abcdef")
|
||||||
|
|
||||||
|
# Issue 6083: Reference counting bug
|
||||||
|
def test_from_dll_refcount(self):
|
||||||
|
class BadSequence(tuple):
|
||||||
|
def __getitem__(self, key):
|
||||||
|
if key == 0:
|
||||||
|
return "my_strchr"
|
||||||
|
if key == 1:
|
||||||
|
return CDLL(_ctypes_test.__file__)
|
||||||
|
raise IndexError
|
||||||
|
|
||||||
|
# _CFuncPtr instances are now callable with a tuple argument
|
||||||
|
# which denotes a function name and a dll:
|
||||||
|
strchr = CFUNCTYPE(c_char_p, c_char_p, c_char)(
|
||||||
|
BadSequence(("my_strchr", CDLL(_ctypes_test.__file__))))
|
||||||
|
self.assertTrue(strchr(b"abcdef", b"b"), "bcdef")
|
||||||
|
self.assertEqual(strchr(b"abcdef", b"x"), None)
|
||||||
|
self.assertRaises(ArgumentError, strchr, b"abcdef", 3.0)
|
||||||
|
self.assertRaises(TypeError, strchr, b"abcdef")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
55
Lib/ctypes/test/test_simplesubclasses.py
vendored
Normal file
55
Lib/ctypes/test/test_simplesubclasses.py
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import unittest
|
||||||
|
from ctypes import *
|
||||||
|
|
||||||
|
class MyInt(c_int):
|
||||||
|
def __eq__(self, other):
|
||||||
|
if type(other) != MyInt:
|
||||||
|
return NotImplementedError
|
||||||
|
return self.value == other.value
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_compare(self):
|
||||||
|
self.assertEqual(MyInt(3), MyInt(3))
|
||||||
|
self.assertNotEqual(MyInt(42), MyInt(43))
|
||||||
|
|
||||||
|
def test_ignore_retval(self):
|
||||||
|
# Test if the return value of a callback is ignored
|
||||||
|
# if restype is None
|
||||||
|
proto = CFUNCTYPE(None)
|
||||||
|
def func():
|
||||||
|
return (1, "abc", None)
|
||||||
|
|
||||||
|
cb = proto(func)
|
||||||
|
self.assertEqual(None, cb())
|
||||||
|
|
||||||
|
|
||||||
|
def test_int_callback(self):
|
||||||
|
args = []
|
||||||
|
def func(arg):
|
||||||
|
args.append(arg)
|
||||||
|
return arg
|
||||||
|
|
||||||
|
cb = CFUNCTYPE(None, MyInt)(func)
|
||||||
|
|
||||||
|
self.assertEqual(None, cb(42))
|
||||||
|
self.assertEqual(type(args[-1]), MyInt)
|
||||||
|
|
||||||
|
cb = CFUNCTYPE(c_int, c_int)(func)
|
||||||
|
|
||||||
|
self.assertEqual(42, cb(42))
|
||||||
|
self.assertEqual(type(args[-1]), int)
|
||||||
|
|
||||||
|
def test_int_struct(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("x", MyInt)]
|
||||||
|
|
||||||
|
self.assertEqual(X().x, MyInt())
|
||||||
|
|
||||||
|
s = X()
|
||||||
|
s.x = MyInt(42)
|
||||||
|
|
||||||
|
self.assertEqual(s.x, MyInt(42))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
33
Lib/ctypes/test/test_sizes.py
vendored
Normal file
33
Lib/ctypes/test/test_sizes.py
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Test specifically-sized containers.
|
||||||
|
|
||||||
|
from ctypes import *
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
class SizesTestCase(unittest.TestCase):
|
||||||
|
def test_8(self):
|
||||||
|
self.assertEqual(1, sizeof(c_int8))
|
||||||
|
self.assertEqual(1, sizeof(c_uint8))
|
||||||
|
|
||||||
|
def test_16(self):
|
||||||
|
self.assertEqual(2, sizeof(c_int16))
|
||||||
|
self.assertEqual(2, sizeof(c_uint16))
|
||||||
|
|
||||||
|
def test_32(self):
|
||||||
|
self.assertEqual(4, sizeof(c_int32))
|
||||||
|
self.assertEqual(4, sizeof(c_uint32))
|
||||||
|
|
||||||
|
def test_64(self):
|
||||||
|
self.assertEqual(8, sizeof(c_int64))
|
||||||
|
self.assertEqual(8, sizeof(c_uint64))
|
||||||
|
|
||||||
|
def test_size_t(self):
|
||||||
|
self.assertEqual(sizeof(c_void_p), sizeof(c_size_t))
|
||||||
|
|
||||||
|
def test_ssize_t(self):
|
||||||
|
self.assertEqual(sizeof(c_void_p), sizeof(c_ssize_t))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
167
Lib/ctypes/test/test_slicing.py
vendored
Normal file
167
Lib/ctypes/test/test_slicing.py
vendored
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
import unittest
|
||||||
|
from ctypes import *
|
||||||
|
from ctypes.test import need_symbol
|
||||||
|
|
||||||
|
import _ctypes_test
|
||||||
|
|
||||||
|
class SlicesTestCase(unittest.TestCase):
|
||||||
|
def test_getslice_cint(self):
|
||||||
|
a = (c_int * 100)(*range(1100, 1200))
|
||||||
|
b = list(range(1100, 1200))
|
||||||
|
self.assertEqual(a[0:2], b[0:2])
|
||||||
|
self.assertEqual(a[0:2:], b[0:2:])
|
||||||
|
self.assertEqual(len(a), len(b))
|
||||||
|
self.assertEqual(a[5:7], b[5:7])
|
||||||
|
self.assertEqual(a[5:7:], b[5:7:])
|
||||||
|
self.assertEqual(a[-1], b[-1])
|
||||||
|
self.assertEqual(a[:], b[:])
|
||||||
|
self.assertEqual(a[::], b[::])
|
||||||
|
self.assertEqual(a[10::-1], b[10::-1])
|
||||||
|
self.assertEqual(a[30:20:-1], b[30:20:-1])
|
||||||
|
self.assertEqual(a[:12:6], b[:12:6])
|
||||||
|
self.assertEqual(a[2:6:4], b[2:6:4])
|
||||||
|
|
||||||
|
a[0:5] = range(5, 10)
|
||||||
|
self.assertEqual(a[0:5], list(range(5, 10)))
|
||||||
|
self.assertEqual(a[0:5:], list(range(5, 10)))
|
||||||
|
self.assertEqual(a[4::-1], list(range(9, 4, -1)))
|
||||||
|
|
||||||
|
def test_setslice_cint(self):
|
||||||
|
a = (c_int * 100)(*range(1100, 1200))
|
||||||
|
b = list(range(1100, 1200))
|
||||||
|
|
||||||
|
a[32:47] = list(range(32, 47))
|
||||||
|
self.assertEqual(a[32:47], list(range(32, 47)))
|
||||||
|
a[32:47] = range(132, 147)
|
||||||
|
self.assertEqual(a[32:47:], list(range(132, 147)))
|
||||||
|
a[46:31:-1] = range(232, 247)
|
||||||
|
self.assertEqual(a[32:47:1], list(range(246, 231, -1)))
|
||||||
|
|
||||||
|
a[32:47] = range(1132, 1147)
|
||||||
|
self.assertEqual(a[:], b)
|
||||||
|
a[32:47:7] = range(3)
|
||||||
|
b[32:47:7] = range(3)
|
||||||
|
self.assertEqual(a[:], b)
|
||||||
|
a[33::-3] = range(12)
|
||||||
|
b[33::-3] = range(12)
|
||||||
|
self.assertEqual(a[:], b)
|
||||||
|
|
||||||
|
from operator import setitem
|
||||||
|
|
||||||
|
# TypeError: int expected instead of str instance
|
||||||
|
self.assertRaises(TypeError, setitem, a, slice(0, 5), "abcde")
|
||||||
|
# TypeError: int expected instead of str instance
|
||||||
|
self.assertRaises(TypeError, setitem, a, slice(0, 5),
|
||||||
|
["a", "b", "c", "d", "e"])
|
||||||
|
# TypeError: int expected instead of float instance
|
||||||
|
self.assertRaises(TypeError, setitem, a, slice(0, 5),
|
||||||
|
[1, 2, 3, 4, 3.14])
|
||||||
|
# ValueError: Can only assign sequence of same size
|
||||||
|
self.assertRaises(ValueError, setitem, a, slice(0, 5), range(32))
|
||||||
|
|
||||||
|
def test_char_ptr(self):
|
||||||
|
s = b"abcdefghijklmnopqrstuvwxyz"
|
||||||
|
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
dll.my_strdup.restype = POINTER(c_char)
|
||||||
|
dll.my_free.restype = None
|
||||||
|
res = dll.my_strdup(s)
|
||||||
|
self.assertEqual(res[:len(s)], s)
|
||||||
|
self.assertEqual(res[:3], s[:3])
|
||||||
|
self.assertEqual(res[:len(s):], s)
|
||||||
|
self.assertEqual(res[len(s)-1:-1:-1], s[::-1])
|
||||||
|
self.assertEqual(res[len(s)-1:5:-7], s[:5:-7])
|
||||||
|
self.assertEqual(res[0:-1:-1], s[0::-1])
|
||||||
|
|
||||||
|
import operator
|
||||||
|
self.assertRaises(ValueError, operator.getitem,
|
||||||
|
res, slice(None, None, None))
|
||||||
|
self.assertRaises(ValueError, operator.getitem,
|
||||||
|
res, slice(0, None, None))
|
||||||
|
self.assertRaises(ValueError, operator.getitem,
|
||||||
|
res, slice(None, 5, -1))
|
||||||
|
self.assertRaises(ValueError, operator.getitem,
|
||||||
|
res, slice(-5, None, None))
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, operator.setitem,
|
||||||
|
res, slice(0, 5), "abcde")
|
||||||
|
dll.my_free(res)
|
||||||
|
|
||||||
|
dll.my_strdup.restype = POINTER(c_byte)
|
||||||
|
res = dll.my_strdup(s)
|
||||||
|
self.assertEqual(res[:len(s)], list(range(ord("a"), ord("z")+1)))
|
||||||
|
self.assertEqual(res[:len(s):], list(range(ord("a"), ord("z")+1)))
|
||||||
|
dll.my_free(res)
|
||||||
|
|
||||||
|
def test_char_ptr_with_free(self):
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
s = b"abcdefghijklmnopqrstuvwxyz"
|
||||||
|
|
||||||
|
class allocated_c_char_p(c_char_p):
|
||||||
|
pass
|
||||||
|
|
||||||
|
dll.my_free.restype = None
|
||||||
|
def errcheck(result, func, args):
|
||||||
|
retval = result.value
|
||||||
|
dll.my_free(result)
|
||||||
|
return retval
|
||||||
|
|
||||||
|
dll.my_strdup.restype = allocated_c_char_p
|
||||||
|
dll.my_strdup.errcheck = errcheck
|
||||||
|
try:
|
||||||
|
res = dll.my_strdup(s)
|
||||||
|
self.assertEqual(res, s)
|
||||||
|
finally:
|
||||||
|
del dll.my_strdup.errcheck
|
||||||
|
|
||||||
|
|
||||||
|
def test_char_array(self):
|
||||||
|
s = b"abcdefghijklmnopqrstuvwxyz\0"
|
||||||
|
|
||||||
|
p = (c_char * 27)(*s)
|
||||||
|
self.assertEqual(p[:], s)
|
||||||
|
self.assertEqual(p[::], s)
|
||||||
|
self.assertEqual(p[::-1], s[::-1])
|
||||||
|
self.assertEqual(p[5::-2], s[5::-2])
|
||||||
|
self.assertEqual(p[2:5:-3], s[2:5:-3])
|
||||||
|
|
||||||
|
|
||||||
|
@need_symbol('c_wchar')
|
||||||
|
def test_wchar_ptr(self):
|
||||||
|
s = "abcdefghijklmnopqrstuvwxyz\0"
|
||||||
|
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
dll.my_wcsdup.restype = POINTER(c_wchar)
|
||||||
|
dll.my_wcsdup.argtypes = POINTER(c_wchar),
|
||||||
|
dll.my_free.restype = None
|
||||||
|
res = dll.my_wcsdup(s[:-1])
|
||||||
|
self.assertEqual(res[:len(s)], s)
|
||||||
|
self.assertEqual(res[:len(s):], s)
|
||||||
|
self.assertEqual(res[len(s)-1:-1:-1], s[::-1])
|
||||||
|
self.assertEqual(res[len(s)-1:5:-7], s[:5:-7])
|
||||||
|
|
||||||
|
import operator
|
||||||
|
self.assertRaises(TypeError, operator.setitem,
|
||||||
|
res, slice(0, 5), "abcde")
|
||||||
|
dll.my_free(res)
|
||||||
|
|
||||||
|
if sizeof(c_wchar) == sizeof(c_short):
|
||||||
|
dll.my_wcsdup.restype = POINTER(c_short)
|
||||||
|
elif sizeof(c_wchar) == sizeof(c_int):
|
||||||
|
dll.my_wcsdup.restype = POINTER(c_int)
|
||||||
|
elif sizeof(c_wchar) == sizeof(c_long):
|
||||||
|
dll.my_wcsdup.restype = POINTER(c_long)
|
||||||
|
else:
|
||||||
|
self.skipTest('Pointers to c_wchar are not supported')
|
||||||
|
res = dll.my_wcsdup(s[:-1])
|
||||||
|
tmpl = list(range(ord("a"), ord("z")+1))
|
||||||
|
self.assertEqual(res[:len(s)-1], tmpl)
|
||||||
|
self.assertEqual(res[:len(s)-1:], tmpl)
|
||||||
|
self.assertEqual(res[len(s)-2:-1:-1], tmpl[::-1])
|
||||||
|
self.assertEqual(res[len(s)-2:5:-7], tmpl[:5:-7])
|
||||||
|
dll.my_free(res)
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
77
Lib/ctypes/test/test_stringptr.py
vendored
Normal file
77
Lib/ctypes/test/test_stringptr.py
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import unittest
|
||||||
|
from test import support
|
||||||
|
from ctypes import *
|
||||||
|
|
||||||
|
import _ctypes_test
|
||||||
|
|
||||||
|
lib = CDLL(_ctypes_test.__file__)
|
||||||
|
|
||||||
|
class StringPtrTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
@support.refcount_test
|
||||||
|
def test__POINTER_c_char(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("str", POINTER(c_char))]
|
||||||
|
x = X()
|
||||||
|
|
||||||
|
# NULL pointer access
|
||||||
|
self.assertRaises(ValueError, getattr, x.str, "contents")
|
||||||
|
b = c_buffer(b"Hello, World")
|
||||||
|
from sys import getrefcount as grc
|
||||||
|
self.assertEqual(grc(b), 2)
|
||||||
|
x.str = b
|
||||||
|
self.assertEqual(grc(b), 3)
|
||||||
|
|
||||||
|
# POINTER(c_char) and Python string is NOT compatible
|
||||||
|
# POINTER(c_char) and c_buffer() is compatible
|
||||||
|
for i in range(len(b)):
|
||||||
|
self.assertEqual(b[i], x.str[i])
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, setattr, x, "str", "Hello, World")
|
||||||
|
|
||||||
|
def test__c_char_p(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("str", c_char_p)]
|
||||||
|
x = X()
|
||||||
|
|
||||||
|
# c_char_p and Python string is compatible
|
||||||
|
# c_char_p and c_buffer is NOT compatible
|
||||||
|
self.assertEqual(x.str, None)
|
||||||
|
x.str = b"Hello, World"
|
||||||
|
self.assertEqual(x.str, b"Hello, World")
|
||||||
|
b = c_buffer(b"Hello, World")
|
||||||
|
self.assertRaises(TypeError, setattr, x, b"str", b)
|
||||||
|
|
||||||
|
|
||||||
|
def test_functions(self):
|
||||||
|
strchr = lib.my_strchr
|
||||||
|
strchr.restype = c_char_p
|
||||||
|
|
||||||
|
# c_char_p and Python string is compatible
|
||||||
|
# c_char_p and c_buffer are now compatible
|
||||||
|
strchr.argtypes = c_char_p, c_char
|
||||||
|
self.assertEqual(strchr(b"abcdef", b"c"), b"cdef")
|
||||||
|
self.assertEqual(strchr(c_buffer(b"abcdef"), b"c"), b"cdef")
|
||||||
|
|
||||||
|
# POINTER(c_char) and Python string is NOT compatible
|
||||||
|
# POINTER(c_char) and c_buffer() is compatible
|
||||||
|
strchr.argtypes = POINTER(c_char), c_char
|
||||||
|
buf = c_buffer(b"abcdef")
|
||||||
|
self.assertEqual(strchr(buf, b"c"), b"cdef")
|
||||||
|
self.assertEqual(strchr(b"abcdef", b"c"), b"cdef")
|
||||||
|
|
||||||
|
# XXX These calls are dangerous, because the first argument
|
||||||
|
# to strchr is no longer valid after the function returns!
|
||||||
|
# So we must keep a reference to buf separately
|
||||||
|
|
||||||
|
strchr.restype = POINTER(c_char)
|
||||||
|
buf = c_buffer(b"abcdef")
|
||||||
|
r = strchr(buf, b"c")
|
||||||
|
x = r[0], r[1], r[2], r[3], r[4]
|
||||||
|
self.assertEqual(x, (b"c", b"d", b"e", b"f", b"\000"))
|
||||||
|
del buf
|
||||||
|
# Because r is a pointer to memory that is freed after deleting buf,
|
||||||
|
# the pointer is hanging and using it would reference freed memory.
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
145
Lib/ctypes/test/test_strings.py
vendored
Normal file
145
Lib/ctypes/test/test_strings.py
vendored
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
import unittest
|
||||||
|
from ctypes import *
|
||||||
|
from ctypes.test import need_symbol
|
||||||
|
|
||||||
|
class StringArrayTestCase(unittest.TestCase):
|
||||||
|
def test(self):
|
||||||
|
BUF = c_char * 4
|
||||||
|
|
||||||
|
buf = BUF(b"a", b"b", b"c")
|
||||||
|
self.assertEqual(buf.value, b"abc")
|
||||||
|
self.assertEqual(buf.raw, b"abc\000")
|
||||||
|
|
||||||
|
buf.value = b"ABCD"
|
||||||
|
self.assertEqual(buf.value, b"ABCD")
|
||||||
|
self.assertEqual(buf.raw, b"ABCD")
|
||||||
|
|
||||||
|
buf.value = b"x"
|
||||||
|
self.assertEqual(buf.value, b"x")
|
||||||
|
self.assertEqual(buf.raw, b"x\000CD")
|
||||||
|
|
||||||
|
buf[1] = b"Z"
|
||||||
|
self.assertEqual(buf.value, b"xZCD")
|
||||||
|
self.assertEqual(buf.raw, b"xZCD")
|
||||||
|
|
||||||
|
self.assertRaises(ValueError, setattr, buf, "value", b"aaaaaaaa")
|
||||||
|
self.assertRaises(TypeError, setattr, buf, "value", 42)
|
||||||
|
|
||||||
|
def test_c_buffer_value(self):
|
||||||
|
buf = c_buffer(32)
|
||||||
|
|
||||||
|
buf.value = b"Hello, World"
|
||||||
|
self.assertEqual(buf.value, b"Hello, World")
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, setattr, buf, "value", memoryview(b"Hello, World"))
|
||||||
|
self.assertRaises(TypeError, setattr, buf, "value", memoryview(b"abc"))
|
||||||
|
self.assertRaises(ValueError, setattr, buf, "raw", memoryview(b"x" * 100))
|
||||||
|
|
||||||
|
def test_c_buffer_raw(self):
|
||||||
|
buf = c_buffer(32)
|
||||||
|
|
||||||
|
buf.raw = memoryview(b"Hello, World")
|
||||||
|
self.assertEqual(buf.value, b"Hello, World")
|
||||||
|
self.assertRaises(TypeError, setattr, buf, "value", memoryview(b"abc"))
|
||||||
|
self.assertRaises(ValueError, setattr, buf, "raw", memoryview(b"x" * 100))
|
||||||
|
|
||||||
|
def test_param_1(self):
|
||||||
|
BUF = c_char * 4
|
||||||
|
buf = BUF()
|
||||||
|
## print c_char_p.from_param(buf)
|
||||||
|
|
||||||
|
def test_param_2(self):
|
||||||
|
BUF = c_char * 4
|
||||||
|
buf = BUF()
|
||||||
|
## print BUF.from_param(c_char_p("python"))
|
||||||
|
## print BUF.from_param(BUF(*"pyth"))
|
||||||
|
|
||||||
|
def test_del_segfault(self):
|
||||||
|
BUF = c_char * 4
|
||||||
|
buf = BUF()
|
||||||
|
with self.assertRaises(AttributeError):
|
||||||
|
del buf.raw
|
||||||
|
|
||||||
|
|
||||||
|
@need_symbol('c_wchar')
|
||||||
|
class WStringArrayTestCase(unittest.TestCase):
|
||||||
|
def test(self):
|
||||||
|
BUF = c_wchar * 4
|
||||||
|
|
||||||
|
buf = BUF("a", "b", "c")
|
||||||
|
self.assertEqual(buf.value, "abc")
|
||||||
|
|
||||||
|
buf.value = "ABCD"
|
||||||
|
self.assertEqual(buf.value, "ABCD")
|
||||||
|
|
||||||
|
buf.value = "x"
|
||||||
|
self.assertEqual(buf.value, "x")
|
||||||
|
|
||||||
|
buf[1] = "Z"
|
||||||
|
self.assertEqual(buf.value, "xZCD")
|
||||||
|
|
||||||
|
@unittest.skipIf(sizeof(c_wchar) < 4,
|
||||||
|
"sizeof(wchar_t) is smaller than 4 bytes")
|
||||||
|
def test_nonbmp(self):
|
||||||
|
u = chr(0x10ffff)
|
||||||
|
w = c_wchar(u)
|
||||||
|
self.assertEqual(w.value, u)
|
||||||
|
|
||||||
|
|
||||||
|
@need_symbol('c_wchar')
|
||||||
|
class WStringTestCase(unittest.TestCase):
|
||||||
|
def test_wchar(self):
|
||||||
|
c_wchar("x")
|
||||||
|
repr(byref(c_wchar("x")))
|
||||||
|
c_wchar("x")
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skip('test disabled')
|
||||||
|
def test_basic_wstrings(self):
|
||||||
|
cs = c_wstring("abcdef")
|
||||||
|
|
||||||
|
# XXX This behaviour is about to change:
|
||||||
|
# len returns the size of the internal buffer in bytes.
|
||||||
|
# This includes the terminating NUL character.
|
||||||
|
self.assertEqual(sizeof(cs), 14)
|
||||||
|
|
||||||
|
# The value property is the string up to the first terminating NUL.
|
||||||
|
self.assertEqual(cs.value, "abcdef")
|
||||||
|
self.assertEqual(c_wstring("abc\000def").value, "abc")
|
||||||
|
|
||||||
|
self.assertEqual(c_wstring("abc\000def").value, "abc")
|
||||||
|
|
||||||
|
# The raw property is the total buffer contents:
|
||||||
|
self.assertEqual(cs.raw, "abcdef\000")
|
||||||
|
self.assertEqual(c_wstring("abc\000def").raw, "abc\000def\000")
|
||||||
|
|
||||||
|
# We can change the value:
|
||||||
|
cs.value = "ab"
|
||||||
|
self.assertEqual(cs.value, "ab")
|
||||||
|
self.assertEqual(cs.raw, "ab\000\000\000\000\000")
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, c_wstring, "123")
|
||||||
|
self.assertRaises(ValueError, c_wstring, 0)
|
||||||
|
|
||||||
|
@unittest.skip('test disabled')
|
||||||
|
def test_toolong(self):
|
||||||
|
cs = c_wstring("abcdef")
|
||||||
|
# Much too long string:
|
||||||
|
self.assertRaises(ValueError, setattr, cs, "value", "123456789012345")
|
||||||
|
|
||||||
|
# One char too long values:
|
||||||
|
self.assertRaises(ValueError, setattr, cs, "value", "1234567")
|
||||||
|
|
||||||
|
|
||||||
|
def run_test(rep, msg, func, arg):
|
||||||
|
items = range(rep)
|
||||||
|
from time import perf_counter as clock
|
||||||
|
start = clock()
|
||||||
|
for i in items:
|
||||||
|
func(arg); func(arg); func(arg); func(arg); func(arg)
|
||||||
|
stop = clock()
|
||||||
|
print("%20s: %.2f us" % (msg, ((stop-start)*1e6/5/rep)))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
97
Lib/ctypes/test/test_struct_fields.py
vendored
Normal file
97
Lib/ctypes/test/test_struct_fields.py
vendored
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import unittest
|
||||||
|
from ctypes import *
|
||||||
|
|
||||||
|
class StructFieldsTestCase(unittest.TestCase):
|
||||||
|
# Structure/Union classes must get 'finalized' sooner or
|
||||||
|
# later, when one of these things happen:
|
||||||
|
#
|
||||||
|
# 1. _fields_ is set.
|
||||||
|
# 2. An instance is created.
|
||||||
|
# 3. The type is used as field of another Structure/Union.
|
||||||
|
# 4. The type is subclassed
|
||||||
|
#
|
||||||
|
# When they are finalized, assigning _fields_ is no longer allowed.
|
||||||
|
|
||||||
|
def test_1_A(self):
|
||||||
|
class X(Structure):
|
||||||
|
pass
|
||||||
|
self.assertEqual(sizeof(X), 0) # not finalized
|
||||||
|
X._fields_ = [] # finalized
|
||||||
|
self.assertRaises(AttributeError, setattr, X, "_fields_", [])
|
||||||
|
|
||||||
|
def test_1_B(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [] # finalized
|
||||||
|
self.assertRaises(AttributeError, setattr, X, "_fields_", [])
|
||||||
|
|
||||||
|
def test_2(self):
|
||||||
|
class X(Structure):
|
||||||
|
pass
|
||||||
|
X()
|
||||||
|
self.assertRaises(AttributeError, setattr, X, "_fields_", [])
|
||||||
|
|
||||||
|
def test_3(self):
|
||||||
|
class X(Structure):
|
||||||
|
pass
|
||||||
|
class Y(Structure):
|
||||||
|
_fields_ = [("x", X)] # finalizes X
|
||||||
|
self.assertRaises(AttributeError, setattr, X, "_fields_", [])
|
||||||
|
|
||||||
|
def test_4(self):
|
||||||
|
class X(Structure):
|
||||||
|
pass
|
||||||
|
class Y(X):
|
||||||
|
pass
|
||||||
|
self.assertRaises(AttributeError, setattr, X, "_fields_", [])
|
||||||
|
Y._fields_ = []
|
||||||
|
self.assertRaises(AttributeError, setattr, X, "_fields_", [])
|
||||||
|
|
||||||
|
def test_5(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = (("char", c_char * 5),)
|
||||||
|
|
||||||
|
x = X(b'#' * 5)
|
||||||
|
x.char = b'a\0b\0'
|
||||||
|
self.assertEqual(bytes(x), b'a\x00###')
|
||||||
|
|
||||||
|
def test_6(self):
|
||||||
|
class X(Structure):
|
||||||
|
_fields_ = [("x", c_int)]
|
||||||
|
CField = type(X.x)
|
||||||
|
self.assertRaises(TypeError, CField)
|
||||||
|
|
||||||
|
def test_gh99275(self):
|
||||||
|
class BrokenStructure(Structure):
|
||||||
|
def __init_subclass__(cls, **kwargs):
|
||||||
|
cls._fields_ = [] # This line will fail, `stgdict` is not ready
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(TypeError,
|
||||||
|
'ctypes state is not initialized'):
|
||||||
|
class Subclass(BrokenStructure): ...
|
||||||
|
|
||||||
|
# __set__ and __get__ should raise a TypeError in case their self
|
||||||
|
# argument is not a ctype instance.
|
||||||
|
def test___set__(self):
|
||||||
|
class MyCStruct(Structure):
|
||||||
|
_fields_ = (("field", c_int),)
|
||||||
|
self.assertRaises(TypeError,
|
||||||
|
MyCStruct.field.__set__, 'wrong type self', 42)
|
||||||
|
|
||||||
|
class MyCUnion(Union):
|
||||||
|
_fields_ = (("field", c_int),)
|
||||||
|
self.assertRaises(TypeError,
|
||||||
|
MyCUnion.field.__set__, 'wrong type self', 42)
|
||||||
|
|
||||||
|
def test___get__(self):
|
||||||
|
class MyCStruct(Structure):
|
||||||
|
_fields_ = (("field", c_int),)
|
||||||
|
self.assertRaises(TypeError,
|
||||||
|
MyCStruct.field.__get__, 'wrong type self', 42)
|
||||||
|
|
||||||
|
class MyCUnion(Union):
|
||||||
|
_fields_ = (("field", c_int),)
|
||||||
|
self.assertRaises(TypeError,
|
||||||
|
MyCUnion.field.__get__, 'wrong type self', 42)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user