Compare commits
1056 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a79f58ba3 | ||
|
|
66ec0a50b6 | ||
|
|
c58b67c540 | ||
|
|
cc793a8575 | ||
|
|
7f5cb46835 | ||
|
|
a7f9e8382b | ||
|
|
39ebdab1bc | ||
|
|
9a6fa33c69 | ||
|
|
2f6555dfd3 | ||
|
|
ff19f273a9 | ||
|
|
04f08b67a4 | ||
|
|
3d0717813a | ||
|
|
d609b635f4 | ||
|
|
0f2d7dc73c | ||
|
|
5c878001ea | ||
|
|
4dc5f7897d | ||
|
|
08de3dad33 | ||
|
|
5748c5ce8f | ||
|
|
b6a302d0a8 | ||
|
|
130f76f66e | ||
|
|
075faa5e2b | ||
|
|
eaa882f3d5 | ||
|
|
ee6c54904b | ||
|
|
2a8463c745 | ||
|
|
1d451c786d | ||
|
|
a36bab448f | ||
|
|
437a6fb224 | ||
|
|
1b16d649f9 | ||
|
|
6f8547cc1a | ||
|
|
b5a94d8e6c | ||
|
|
65bc43dc56 | ||
|
|
c55635d42a | ||
|
|
93fdad28aa | ||
|
|
48215fdcb9 | ||
|
|
5a6a580765 | ||
|
|
df17bb2bd3 | ||
|
|
6eb7af5a4e | ||
|
|
bc25d51b2f | ||
|
|
9ed1289b01 | ||
|
|
5a0c9aca63 | ||
|
|
da2c2e8492 | ||
|
|
74cfdc5feb | ||
|
|
b4e0265622 | ||
|
|
210ad22dbe | ||
|
|
6c519b1280 | ||
|
|
57a55cd0a3 | ||
|
|
d4bf2ff8f5 | ||
|
|
3e08c4ee64 | ||
|
|
703e4b11ba | ||
|
|
3e1590bcfc | ||
|
|
86fc31db8d | ||
|
|
b60376dc28 | ||
|
|
3b9e063fe8 | ||
|
|
9aacb4635e | ||
|
|
d41119ed04 | ||
|
|
afde9f07f7 | ||
|
|
b4cd010d71 | ||
|
|
45e7703133 | ||
|
|
d70e910b65 | ||
|
|
c55db1faac | ||
|
|
16583a6d43 | ||
|
|
7985eff5b4 | ||
|
|
5072226f69 | ||
|
|
6c8d46d8ea | ||
|
|
7d0c9837ce | ||
|
|
8e17e32253 | ||
|
|
f0b855369c | ||
|
|
4aa7ebaf52 | ||
|
|
486b786cb2 | ||
|
|
674879976f | ||
|
|
d4065a9166 | ||
|
|
e7f75f69f2 | ||
|
|
5be85a1f55 | ||
|
|
bb626fe8a7 | ||
|
|
45faaeca7a | ||
|
|
11fb384efb | ||
|
|
5edad01d4e | ||
|
|
f5361a302c | ||
|
|
94e62dfc50 | ||
|
|
afe4800daf | ||
|
|
2cd159e8c5 | ||
|
|
718ba83600 | ||
|
|
1b2f4f4483 | ||
|
|
f68bab06b4 | ||
|
|
a4425cb4af | ||
|
|
01d2d81d1f | ||
|
|
f14e097635 | ||
|
|
a59f677d93 | ||
|
|
36614b0a3d | ||
|
|
b4370c08b9 | ||
|
|
aa51fcb2b6 | ||
|
|
4914135fdf | ||
|
|
84b37e1b57 | ||
|
|
fa76a5c8fe | ||
|
|
27651f4032 | ||
|
|
413b1aa4e9 | ||
|
|
dca77b2273 | ||
|
|
35f53a7353 | ||
|
|
e6a86e0f4c | ||
|
|
b03b387861 | ||
|
|
a5cf55dd4a | ||
|
|
63ef46dd91 | ||
|
|
7834b45002 | ||
|
|
ccaa979f27 | ||
|
|
1a880be85b | ||
|
|
c258fe1459 | ||
|
|
08aed1a6bf | ||
|
|
b49e9191ac | ||
|
|
febccae037 | ||
|
|
d2bf0bf9bb | ||
|
|
5ba0663827 | ||
|
|
63368e07ea | ||
|
|
0b2b73c36a | ||
|
|
69b1c2d4f6 | ||
|
|
4a92011e6e | ||
|
|
6e62fc98ff | ||
|
|
132fb61eba | ||
|
|
03850cf962 | ||
|
|
f05230c679 | ||
|
|
d61a7670a1 | ||
|
|
8d56641590 | ||
|
|
2a480c59ae | ||
|
|
6ea4c12da7 | ||
|
|
f0084608cc | ||
|
|
cefeba33ef | ||
|
|
3318e53d01 | ||
|
|
1cc79ffc10 | ||
|
|
d8015764e6 | ||
|
|
48c99f62e3 | ||
|
|
8ff8a82c51 | ||
|
|
bb8984f5ed | ||
|
|
159cd39777 | ||
|
|
857098fe0f | ||
|
|
283ac8bbf4 | ||
|
|
6626d2aef9 | ||
|
|
ba7cad3962 | ||
|
|
36f6687b70 | ||
|
|
86def48b25 | ||
|
|
0024b71f1c | ||
|
|
17a43dc4a5 | ||
|
|
958f146125 | ||
|
|
13a6f63cd9 | ||
|
|
aa95a425d7 | ||
|
|
015626ce69 | ||
|
|
f9a908abb8 | ||
|
|
160c309371 | ||
|
|
f79b0324fe | ||
|
|
37ee4fbc48 | ||
|
|
888fcbc4b4 | ||
|
|
10a7160549 | ||
|
|
a4daac7eb0 | ||
|
|
97be076f29 | ||
|
|
3d60f955f0 | ||
|
|
659c044372 | ||
|
|
6e8e3c967a | ||
|
|
78c900448e | ||
|
|
372bcdba0c | ||
|
|
d1ba19acad | ||
|
|
2241c98b18 | ||
|
|
715337011b | ||
|
|
e012dbe346 | ||
|
|
5bd8561016 | ||
|
|
846d91fb95 | ||
|
|
0cd74dc324 | ||
|
|
ec2d8223cf | ||
|
|
4df8f2b153 | ||
|
|
5d4fe87b72 | ||
|
|
f17dfa4292 | ||
|
|
ab91771efc | ||
|
|
ef34de960c | ||
|
|
db24723b61 | ||
|
|
e534cc81a3 | ||
|
|
3582e1f6be | ||
|
|
a8ad89cdb3 | ||
|
|
48bcc3419f | ||
|
|
1fcadeb2ce | ||
|
|
2018cf12b1 | ||
|
|
ba407b5eb6 | ||
|
|
ad0b4330e7 | ||
|
|
9aa2a83785 | ||
|
|
0762666bd1 | ||
|
|
7c0c91a7a2 | ||
|
|
9326759a63 | ||
|
|
4d847593b3 | ||
|
|
9a62ebf490 | ||
|
|
211f3c47b5 | ||
|
|
a2974dd067 | ||
|
|
77128ee2dc | ||
|
|
7454a381e2 | ||
|
|
e4a52c1795 | ||
|
|
802da781c6 | ||
|
|
3fc2c94b5e | ||
|
|
daf1de0fed | ||
|
|
e5eba8419a | ||
|
|
6a81aae4f2 | ||
|
|
8ca9321940 | ||
|
|
faded25ee8 | ||
|
|
dbb1b5a227 | ||
|
|
8805036fd8 | ||
|
|
ee51fa5881 | ||
|
|
2cb7e725ce | ||
|
|
02315c0489 | ||
|
|
a92a51b01b | ||
|
|
159ea9b7c0 | ||
|
|
775fb96ac3 | ||
|
|
ced1316bc8 | ||
|
|
5e56e9b4f6 | ||
|
|
2d06ae0f65 | ||
|
|
99015bfc86 | ||
|
|
180ae09202 | ||
|
|
e8feee0612 | ||
|
|
f1a1695aaa | ||
|
|
2707221559 | ||
|
|
360d608da4 | ||
|
|
f1c9efc358 | ||
|
|
804392e5f2 | ||
|
|
0a3cd881f6 | ||
|
|
09e5a226dc | ||
|
|
2efaf39ed8 | ||
|
|
7656581302 | ||
|
|
bfe773bfc8 | ||
|
|
a5d9fbe2b0 | ||
|
|
34afded06d | ||
|
|
3998b70ff6 | ||
|
|
060f047a7e | ||
|
|
2962c7367c | ||
|
|
0a4200bbb3 | ||
|
|
b45006e9a3 | ||
|
|
671ab5a36c | ||
|
|
f1f4c8c104 | ||
|
|
6cfed00a61 | ||
|
|
ff3d13ed0e | ||
|
|
d895f5d6fc | ||
|
|
e97bd87ee2 | ||
|
|
242fb7852b | ||
|
|
1ec99132e6 | ||
|
|
dcbba381d4 | ||
|
|
db581eabcb | ||
|
|
0e83e4f292 | ||
|
|
21ada0fa23 | ||
|
|
a1ff758d0d | ||
|
|
ed118d7f20 | ||
|
|
5ecff65285 | ||
|
|
fc4f769888 | ||
|
|
f78953fd81 | ||
|
|
d7d4afea17 | ||
|
|
5a53b9aabb | ||
|
|
91d99affb7 | ||
|
|
3bca983a95 | ||
|
|
9edcb7edc6 | ||
|
|
6c2739d1e6 | ||
|
|
4e717eb626 | ||
|
|
beacecf29b | ||
|
|
b148770066 | ||
|
|
f3c87a77a7 | ||
|
|
6f95189cf7 | ||
|
|
add5ce0fb8 | ||
|
|
59e7fd478e | ||
|
|
9e24b09a9f | ||
|
|
d03e38941b | ||
|
|
672239b149 | ||
|
|
9b449eee15 | ||
|
|
c1d73bb535 | ||
|
|
a4cf380343 | ||
|
|
f61d0525a5 | ||
|
|
86d6804e60 | ||
|
|
1fff81e21d | ||
|
|
93847bfeb4 | ||
|
|
a754f00ae7 | ||
|
|
278d8ac74e | ||
|
|
17468fc99c | ||
|
|
b66019202e | ||
|
|
965a030564 | ||
|
|
2f47624b19 | ||
|
|
3c3fc3bb9d | ||
|
|
42c84f4f30 | ||
|
|
fbcf1a90c9 | ||
|
|
97f9a8bfdf | ||
|
|
161d4e5fe4 | ||
|
|
c34dde7a3f | ||
|
|
1b535387bf | ||
|
|
7e53f9432c | ||
|
|
b2b629f462 | ||
|
|
cbb2c55dea | ||
|
|
9517c3a2aa | ||
|
|
4175ed8b43 | ||
|
|
87f2003245 | ||
|
|
2612d967f8 | ||
|
|
37a52607c2 | ||
|
|
51c0256cd4 | ||
|
|
f8791c9246 | ||
|
|
02bec7a3bb | ||
|
|
4459aa3d8b | ||
|
|
2e347643a3 | ||
|
|
8629ef6a78 | ||
|
|
5e92644f94 | ||
|
|
3198596f8a | ||
|
|
68375513f3 | ||
|
|
61b8ea8656 | ||
|
|
0557ab431f | ||
|
|
8035f6cced | ||
|
|
0302622310 | ||
|
|
3909225bf9 | ||
|
|
e71d907d34 | ||
|
|
d2e533b8a3 | ||
|
|
54b15f5826 | ||
|
|
d2dbbd4caa | ||
|
|
5f9bc557ea | ||
|
|
543bac925a | ||
|
|
2fe56b97c9 | ||
|
|
3284d575e8 | ||
|
|
a406ca14d6 | ||
|
|
2e5337f5e3 | ||
|
|
74884b1901 | ||
|
|
c67f45b716 | ||
|
|
50e682d2db | ||
|
|
5e5935759e | ||
|
|
45b6b7df92 | ||
|
|
c9b9d796e6 | ||
|
|
09ce84e64e | ||
|
|
8243900960 | ||
|
|
c0fe4d483d | ||
|
|
18a47bfd22 | ||
|
|
3979f9ba3a | ||
|
|
443888248a | ||
|
|
69d49f18e9 | ||
|
|
8b7e6df73d | ||
|
|
9c2203d381 | ||
|
|
df3a4111a9 | ||
|
|
988ace9eb2 | ||
|
|
ed8b1efc16 | ||
|
|
f7178654e5 | ||
|
|
f1df6c5a60 | ||
|
|
66009b0f91 | ||
|
|
215c6b281e | ||
|
|
adcb28f61b | ||
|
|
111c6d6a22 | ||
|
|
7ba8a4ee75 | ||
|
|
400558cc9c | ||
|
|
918dffba96 | ||
|
|
44e2715529 | ||
|
|
b53c4246ef | ||
|
|
e73d4f4e1f | ||
|
|
e7bce90d29 | ||
|
|
623bab4447 | ||
|
|
70f93263e9 | ||
|
|
749288dcb6 | ||
|
|
6fa9768545 | ||
|
|
6b4565f8d1 | ||
|
|
6d4e72e1eb | ||
|
|
162557c2b2 | ||
|
|
d4c3850231 | ||
|
|
28df322500 | ||
|
|
d6ddeb395b | ||
|
|
c4430e4354 | ||
|
|
fbf01bd31a | ||
|
|
e42fe5f0f9 | ||
|
|
ade7ad25c7 | ||
|
|
27c4de242f | ||
|
|
e8368e6c2e | ||
|
|
fac8208e8f | ||
|
|
9879ac5911 | ||
|
|
51abdb80db | ||
|
|
25399da904 | ||
|
|
54884b8c87 | ||
|
|
65534682aa | ||
|
|
e980fbbe39 | ||
|
|
07e768ab68 | ||
|
|
9a2e0c061d | ||
|
|
056d9e8dc2 | ||
|
|
46f5d7a1bb | ||
|
|
30453057e8 | ||
|
|
08831396a5 | ||
|
|
1549d61379 | ||
|
|
f501d0021c | ||
|
|
a506052d12 | ||
|
|
99aab2c3f5 | ||
|
|
3b757b1b8c | ||
|
|
14a9b1ec83 | ||
|
|
ea854086e1 | ||
|
|
0a5a6c19be | ||
|
|
90638b661d | ||
|
|
8239103aa9 | ||
|
|
a2a64546eb | ||
|
|
9fcbf57163 | ||
|
|
dab96cbf27 | ||
|
|
1fb2457018 | ||
|
|
92219e576b | ||
|
|
143ac5af99 | ||
|
|
409b919fc0 | ||
|
|
eadd15fe45 | ||
|
|
3f7223af44 | ||
|
|
a968c0fa05 | ||
|
|
5cb72b6188 | ||
|
|
20085542e2 | ||
|
|
94050a8aaf | ||
|
|
9479bda392 | ||
|
|
cfaf3600c1 | ||
|
|
f6ad25928e | ||
|
|
a6762f7328 | ||
|
|
4e405dd9f9 | ||
|
|
d196ab45d3 | ||
|
|
188df8100c | ||
|
|
e8f9a91056 | ||
|
|
44fa5a77d4 | ||
|
|
31476c69ab | ||
|
|
6200920dc3 | ||
|
|
46c5d5355e | ||
|
|
39024a7536 | ||
|
|
307cd6630f | ||
|
|
ae62ced080 | ||
|
|
6166151ee4 | ||
|
|
da3f4045e7 | ||
|
|
c21eb72924 | ||
|
|
f4cc45bb41 | ||
|
|
7f2dd74ae9 | ||
|
|
c032d4c5d5 | ||
|
|
e865f2a235 | ||
|
|
8d90591b33 | ||
|
|
14cd1e9d94 | ||
|
|
fbc45be83f | ||
|
|
0a3c80e959 | ||
|
|
bedceaacc4 | ||
|
|
1127d519db | ||
|
|
9959164c9a | ||
|
|
60358b6db8 | ||
|
|
b5ac61657a | ||
|
|
0f58fc881b | ||
|
|
2cd69cf632 | ||
|
|
935dd3aaa5 | ||
|
|
c8d24739ed | ||
|
|
be2e3a973e | ||
|
|
cef0423b27 | ||
|
|
de2de00de9 | ||
|
|
25a3e9296a | ||
|
|
cf40c0743c | ||
|
|
c31e1a3797 | ||
|
|
48548767fc | ||
|
|
7536e949b1 | ||
|
|
287c003cfd | ||
|
|
aa53e37fa2 | ||
|
|
54e63b7dd5 | ||
|
|
dd97c94035 | ||
|
|
264e455410 | ||
|
|
75f11f0b65 | ||
|
|
45d0a21294 | ||
|
|
147b43f832 | ||
|
|
7336dbb979 | ||
|
|
6e14585ca2 | ||
|
|
567b1ea7a1 | ||
|
|
d838193d2d | ||
|
|
d844ad18c2 | ||
|
|
3d4d0a2614 | ||
|
|
7a62619a75 | ||
|
|
dae74b674e | ||
|
|
2a99e5dd2a | ||
|
|
8b49ddfa58 | ||
|
|
9361d48b61 | ||
|
|
ebddac6a5c | ||
|
|
b319375592 | ||
|
|
f8fdf0ae91 | ||
|
|
053fc118b7 | ||
|
|
97bb6abcfa | ||
|
|
acda6c46fb | ||
|
|
ac7eb63a6b | ||
|
|
51ece00923 | ||
|
|
b486e1294b | ||
|
|
3bc8b50a0d | ||
|
|
81fa547fa8 | ||
|
|
9d879bee36 | ||
|
|
069f32a8c4 | ||
|
|
4131d3f300 | ||
|
|
254e357076 | ||
|
|
f263932883 | ||
|
|
0f6879bf5e | ||
|
|
bfe2cbe875 | ||
|
|
69d608aec3 | ||
|
|
dfbaa20240 | ||
|
|
fa8354e872 | ||
|
|
00d3001138 | ||
|
|
05faa69c37 | ||
|
|
b1abe5db23 | ||
|
|
774c539f1a | ||
|
|
df2f019997 | ||
|
|
6bc45d158d | ||
|
|
371eb8c6af | ||
|
|
82cdc487ce | ||
|
|
435b8ddc7c | ||
|
|
3cbf0c8ec0 | ||
|
|
9849022eb2 | ||
|
|
18c84a1904 | ||
|
|
6496131b79 | ||
|
|
dff0500114 | ||
|
|
247cdb835a | ||
|
|
ce1872e7e8 | ||
|
|
d845af7b24 | ||
|
|
391553887b | ||
|
|
7656fc8320 | ||
|
|
b6166dccb4 | ||
|
|
e7bcc854d9 | ||
|
|
ffee213c85 | ||
|
|
e5b527d0e3 | ||
|
|
063e2da967 | ||
|
|
da5882c2d5 | ||
|
|
c04e248de5 | ||
|
|
d776e5610e | ||
|
|
bba258aa5e | ||
|
|
3685c1bc01 | ||
|
|
a4cbd03535 | ||
|
|
71367881ed | ||
|
|
ad7d63df97 | ||
|
|
eea169e515 | ||
|
|
0b71255dda | ||
|
|
ce0a9aadec | ||
|
|
16c52f05f1 | ||
|
|
f72182977d | ||
|
|
ed12cf3fb3 | ||
|
|
40d0ade2d9 | ||
|
|
29a074eae3 | ||
|
|
1a650a9eb9 | ||
|
|
ea06c1345f | ||
|
|
00d8787bb8 | ||
|
|
67558e0e22 | ||
|
|
7152707280 | ||
|
|
2d0c1e941e | ||
|
|
42c1f85257 | ||
|
|
0d15a46863 | ||
|
|
570edb466b | ||
|
|
7c80c81433 | ||
|
|
9202ba91cf | ||
|
|
ea8997a108 | ||
|
|
867344d0d7 | ||
|
|
e64feaba7a | ||
|
|
74633815aa | ||
|
|
c0ef4a4d35 | ||
|
|
e289c60c3a | ||
|
|
8c81722a0c | ||
|
|
3425edd2a5 | ||
|
|
37d836d754 | ||
|
|
4458e65fe7 | ||
|
|
3eb6cad222 | ||
|
|
936651702b | ||
|
|
9f1772e679 | ||
|
|
741b571f3b | ||
|
|
653abad27b | ||
|
|
949a620d3a | ||
|
|
89a55d85a9 | ||
|
|
ef7df8f167 | ||
|
|
90a8faabba | ||
|
|
e12a588c39 | ||
|
|
547070e2d8 | ||
|
|
f2fb841b29 | ||
|
|
3256fa9ee9 | ||
|
|
dc9a9ec4c2 | ||
|
|
527845ef29 | ||
|
|
489e638b4e | ||
|
|
13ee1cffed | ||
|
|
4c148bd0ef | ||
|
|
71a7b3c062 | ||
|
|
ebab1b6c69 | ||
|
|
49773b573f | ||
|
|
32979def7d | ||
|
|
ab00c3e911 | ||
|
|
6e4efccc38 | ||
|
|
269eeec702 | ||
|
|
0e1be01b7a | ||
|
|
aff463a3c4 | ||
|
|
b3247c1d03 | ||
|
|
169635e889 | ||
|
|
cd0b2ace67 | ||
|
|
17a1ed5edf | ||
|
|
a54cd4c2fd | ||
|
|
77de45cce3 | ||
|
|
d550c33cd0 | ||
|
|
a58099022a | ||
|
|
3bc7ced97a | ||
|
|
8979b2a9d7 | ||
|
|
d4c11e58aa | ||
|
|
7f83605c81 | ||
|
|
37b41de779 | ||
|
|
bf2c10c810 | ||
|
|
4285325cb8 | ||
|
|
2a1b1107c5 | ||
|
|
cbbd606b6c | ||
|
|
ace772c743 | ||
|
|
3a004a4507 | ||
|
|
a24ca9872f | ||
|
|
503e00f7ff | ||
|
|
0cfa975930 | ||
|
|
b8be339632 | ||
|
|
2aad8c0fce | ||
|
|
15cbd61159 | ||
|
|
2f955e0c99 | ||
|
|
af37778b0d | ||
|
|
3f5e9ea71e | ||
|
|
443275f025 | ||
|
|
8426c57a9e | ||
|
|
30ca9f9d38 | ||
|
|
46d87deb5d | ||
|
|
203508d9f3 | ||
|
|
2c7f94fdb9 | ||
|
|
ff90c9e237 | ||
|
|
b4e8861aa5 | ||
|
|
baa189f5a3 | ||
|
|
a7066ba837 | ||
|
|
113bfb6be8 | ||
|
|
9f4688e549 | ||
|
|
3a9d0b26d5 | ||
|
|
a5e60b6a2d | ||
|
|
0df42b4426 | ||
|
|
0d96a5bf90 | ||
|
|
060f68bd90 | ||
|
|
e5739a3115 | ||
|
|
8a8797df80 | ||
|
|
8994603d46 | ||
|
|
5c0b340a4b | ||
|
|
196dcc37a8 | ||
|
|
83034bbd48 | ||
|
|
0ab57c4139 | ||
|
|
29a7b5e064 | ||
|
|
27ae270159 | ||
|
|
2e40a8b3ca | ||
|
|
18e053546c | ||
|
|
9dbcac9af3 | ||
|
|
4a436572a8 | ||
|
|
97a4967b03 | ||
|
|
8f6a5928f7 | ||
|
|
5d89a93977 | ||
|
|
c53b72fd7b | ||
|
|
6bb739516f | ||
|
|
8d735f3e1d | ||
|
|
aca1b06747 | ||
|
|
8dcd2718aa | ||
|
|
5ad1313b8a | ||
|
|
3b3d237f07 | ||
|
|
c4c968fe69 | ||
|
|
0b6df94b12 | ||
|
|
c3d420bf75 | ||
|
|
ebb4c47155 | ||
|
|
7ea5a22657 | ||
|
|
cd76366d87 | ||
|
|
931e8830ba | ||
|
|
621374679b | ||
|
|
8be1136d03 | ||
|
|
e0b63e34fa | ||
|
|
a7c39c894b | ||
|
|
4a18d76160 | ||
|
|
86f01967e1 | ||
|
|
d784155fd2 | ||
|
|
1fd67c9000 | ||
|
|
e3406e0818 | ||
|
|
dc79116de3 | ||
|
|
8433e2ba04 | ||
|
|
86e1b44230 | ||
|
|
5d3f7d7142 | ||
|
|
648d5d0c6b | ||
|
|
dff597dcd0 | ||
|
|
076fb56f85 | ||
|
|
150537d5e0 | ||
|
|
d8c23fd39b | ||
|
|
b748576358 | ||
|
|
f555a3a76c | ||
|
|
1f4831a23f | ||
|
|
0a0d97aeb5 | ||
|
|
4a3863c2e2 | ||
|
|
d314691fd3 | ||
|
|
01e37fe892 | ||
|
|
abbdb60051 | ||
|
|
5939b336cd | ||
|
|
3d289b803d | ||
|
|
4a704bbb55 | ||
|
|
ee6c9f50a2 | ||
|
|
3181718fe0 | ||
|
|
2674f352e8 | ||
|
|
6fb46a0e79 | ||
|
|
820ea6d68f | ||
|
|
b0032ba2b3 | ||
|
|
cf9b31bd5a | ||
|
|
b68b80aec9 | ||
|
|
bd1d17e8de | ||
|
|
93306f6a5e | ||
|
|
962aede290 | ||
|
|
a8d3d329ec | ||
|
|
b256cd2a6a | ||
|
|
b6b36bc167 | ||
|
|
3dd24f8d21 | ||
|
|
794fb193ba | ||
|
|
d7e1f037d9 | ||
|
|
29ff9301d8 | ||
|
|
f3c666db3c | ||
|
|
b93aa5e35f | ||
|
|
bc66f7e43f | ||
|
|
cb6b851780 | ||
|
|
afb8a4e35d | ||
|
|
06a182386b | ||
|
|
fac07c1b3f | ||
|
|
e8c0ca4f08 | ||
|
|
ac6f257efc | ||
|
|
554cb8d09c | ||
|
|
25b504b4f0 | ||
|
|
0a6e086f9d | ||
|
|
f24c470403 | ||
|
|
52a7ccef57 | ||
|
|
bd2d0d2c3c | ||
|
|
08997279f4 | ||
|
|
205e29d843 | ||
|
|
672c901c70 | ||
|
|
c70efaa0fb | ||
|
|
d370e7788d | ||
|
|
0d83dd1b31 | ||
|
|
ed293ec3e9 | ||
|
|
2f8427bb4e | ||
|
|
94608c6110 | ||
|
|
afc607cfd8 | ||
|
|
30729b7c3c | ||
|
|
dfc5399cd7 | ||
|
|
76489d30f7 | ||
|
|
d6f75d2836 | ||
|
|
d85a3ca19a | ||
|
|
f3c9c6e8a8 | ||
|
|
67bd60d5c6 | ||
|
|
28a93b9eeb | ||
|
|
70461d1ead | ||
|
|
73eccb4c36 | ||
|
|
d7a76a4d07 | ||
|
|
924b5e2e3d | ||
|
|
d87279115d | ||
|
|
0a2735a275 | ||
|
|
c90e76c371 | ||
|
|
370daf0441 | ||
|
|
586ecea6f2 | ||
|
|
db4df5833a | ||
|
|
b17c6e5f89 | ||
|
|
c3f63ac143 | ||
|
|
3862b0b28d | ||
|
|
476d4df1b7 | ||
|
|
52449903c3 | ||
|
|
506c9c91c0 | ||
|
|
38f34e2fa1 | ||
|
|
ba41015ef6 | ||
|
|
ebfc1c49d1 | ||
|
|
45e7734b1a | ||
|
|
8ce6e39b1c | ||
|
|
c8e7d1ae34 | ||
|
|
7b5d4d01ed | ||
|
|
a4f4579f19 | ||
|
|
e4da9bacdf | ||
|
|
1e295535c3 | ||
|
|
3ca1e4b7f0 | ||
|
|
dc19624248 | ||
|
|
f8f1a52ea0 | ||
|
|
5c6d7739bc | ||
|
|
771b5c8852 | ||
|
|
fc5ec5807e | ||
|
|
fc544dc660 | ||
|
|
7792587b3f | ||
|
|
c2cd239d35 | ||
|
|
cb0ba18f53 | ||
|
|
3b85e0c3a9 | ||
|
|
73bc6bacfa | ||
|
|
8e8a953ac6 | ||
|
|
852b96714e | ||
|
|
dd64f1a4a9 | ||
|
|
41a6ec6f31 | ||
|
|
7feab7391d | ||
|
|
f0bfe9de3d | ||
|
|
596937e610 | ||
|
|
57fcd3f57e | ||
|
|
65f5383106 | ||
|
|
964c29cb93 | ||
|
|
38fb6aae78 | ||
|
|
1c5b887dfd | ||
|
|
ba209b5230 | ||
|
|
b62fd79c0c | ||
|
|
655146e522 | ||
|
|
88f2cc9b64 | ||
|
|
ed2bb9d723 | ||
|
|
2a111ff700 | ||
|
|
5c6758fde4 | ||
|
|
9bd8420a6b | ||
|
|
cbdab02d05 | ||
|
|
ce30896cd2 | ||
|
|
2e8b0a83fe | ||
|
|
369c711f14 | ||
|
|
cf0cac3b73 | ||
|
|
a9dd37f429 | ||
|
|
294729962d | ||
|
|
4de433e280 | ||
|
|
652936f47f | ||
|
|
1fe2e2cb03 | ||
|
|
e66473853c | ||
|
|
70f1e3b4b0 | ||
|
|
fdd4abb88a | ||
|
|
fdfc1946da | ||
|
|
5085aa2bce | ||
|
|
912330a7e2 | ||
|
|
88ed1ab648 | ||
|
|
191e8c6d9b | ||
|
|
6bbd741039 | ||
|
|
0f5fb7ed05 | ||
|
|
5f1a7330b2 | ||
|
|
2a75ae46c3 | ||
|
|
89cf943e04 | ||
|
|
833f33fa0c | ||
|
|
3dbac17d75 | ||
|
|
6843d45c51 | ||
|
|
4a840a7c09 | ||
|
|
9b7e4ab0c6 | ||
|
|
4ea7bbc197 | ||
|
|
4d2f05e4b9 | ||
|
|
454b60b6c5 | ||
|
|
f6be23b68b | ||
|
|
644fdc5237 | ||
|
|
4b5f0d5ffa | ||
|
|
9f7ba00611 | ||
|
|
796db80ca4 | ||
|
|
d95c8a2204 | ||
|
|
4678cbeb91 | ||
|
|
67ad0fa364 | ||
|
|
6cdd851227 | ||
|
|
c58715371c | ||
|
|
d5f038e29a | ||
|
|
6eeacaba3e | ||
|
|
6b90ad4d4b | ||
|
|
e273f5399d | ||
|
|
0de1a65644 | ||
|
|
95de11a44e | ||
|
|
05cfdcc8cb | ||
|
|
0ddd3e2839 | ||
|
|
aa9a02ec44 | ||
|
|
e97c774f8e | ||
|
|
f50ace7c0a | ||
|
|
49c0c599b0 | ||
|
|
e0d236c031 | ||
|
|
b533c2600a | ||
|
|
dc574c60ef | ||
|
|
1d26f3730f | ||
|
|
27935ebec9 | ||
|
|
378eb5d67b | ||
|
|
5e71ffab87 | ||
|
|
8df7ed12c1 | ||
|
|
f05333ab75 | ||
|
|
c8d52b633b | ||
|
|
2455f8670e | ||
|
|
3a5dbabf60 | ||
|
|
3441084bd2 | ||
|
|
8b92527d7d | ||
|
|
dab889304e | ||
|
|
7a7cb8c8c5 | ||
|
|
77bd0aa02f | ||
|
|
b0f558da44 | ||
|
|
ca1f4bc537 | ||
|
|
219b758949 | ||
|
|
6161bcff6e | ||
|
|
99a4a93dbc | ||
|
|
99ba3c9700 | ||
|
|
c19708b193 | ||
|
|
1f08d990d5 | ||
|
|
e2c59d3282 | ||
|
|
f9029f11af | ||
|
|
c7be83ac47 | ||
|
|
74aaf91653 | ||
|
|
1aeb58b531 | ||
|
|
7b3febd314 | ||
|
|
e87ff07370 | ||
|
|
a220a40350 | ||
|
|
dd6c534468 | ||
|
|
4a0aea2deb | ||
|
|
8f90812481 | ||
|
|
3b3bf9f53d | ||
|
|
54cea3d178 | ||
|
|
9628c71210 | ||
|
|
685387a43e | ||
|
|
a6f2d2d2c9 | ||
|
|
6d3fe0b826 | ||
|
|
bdad345f99 | ||
|
|
063335a715 | ||
|
|
f074fd9ac6 | ||
|
|
6550b9911b | ||
|
|
258031afe5 | ||
|
|
d1af369800 | ||
|
|
99496d9e5b | ||
|
|
983a09a2d4 | ||
|
|
0108f262b1 | ||
|
|
c47dcaa713 | ||
|
|
c33074c8b9 | ||
|
|
e351976ef4 | ||
|
|
b18a9deb4c | ||
|
|
d7e8eeef56 | ||
|
|
e58e8faf47 | ||
|
|
7d43225c36 | ||
|
|
460cae02b0 | ||
|
|
f3a119c06a | ||
|
|
d1aa553f73 | ||
|
|
07b2b18a01 | ||
|
|
766de67392 | ||
|
|
821f9a94d8 | ||
|
|
cb30848e5a | ||
|
|
8e178e9f9b | ||
|
|
8e28815d44 | ||
|
|
b27dde24d6 | ||
|
|
4a436f2255 | ||
|
|
def471b975 | ||
|
|
f743e95cfc | ||
|
|
4e581b637f | ||
|
|
6b86b0dbfe | ||
|
|
6821d36ca5 | ||
|
|
083084fcbc | ||
|
|
f7387e45ea | ||
|
|
3da28067f3 | ||
|
|
5c71151967 | ||
|
|
3f9f4be070 | ||
|
|
a7a39f1364 | ||
|
|
e81b275eda | ||
|
|
537fc3c315 | ||
|
|
cfd16d0dac | ||
|
|
00d3abe6dc | ||
|
|
71c76d96d3 | ||
|
|
843872b501 | ||
|
|
eaf38c7239 | ||
|
|
b29a9711c4 | ||
|
|
c750a5beec | ||
|
|
df37cdf51f | ||
|
|
af75ca435b | ||
|
|
8aed5fecd9 | ||
|
|
f3261d9418 | ||
|
|
775f4a6f2f | ||
|
|
502652ff02 | ||
|
|
0e83511d6d | ||
|
|
815dd19fb4 | ||
|
|
1f3ab118fa | ||
|
|
0ec72d0745 | ||
|
|
69f3bd8336 | ||
|
|
10a3b9118b | ||
|
|
ce8c829945 | ||
|
|
ed7aa074aa | ||
|
|
66e9a79472 | ||
|
|
1480aed781 | ||
|
|
be0e2132b7 | ||
|
|
7113c76f0d | ||
|
|
ef732fc51d | ||
|
|
dd45f8ba6c | ||
|
|
c486598440 | ||
|
|
059455b45d | ||
|
|
73ff53c742 | ||
|
|
88366b393c | ||
|
|
9b0ce535c9 | ||
|
|
8a6bdb282f | ||
|
|
459cc40192 | ||
|
|
e3b73682b2 | ||
|
|
8480075f01 | ||
|
|
9ad2b75038 | ||
|
|
a33650953a | ||
|
|
667e70f555 | ||
|
|
0668a6c6d3 | ||
|
|
03ce0adb79 | ||
|
|
e7a4d3d8cf | ||
|
|
61eb20df71 | ||
|
|
df6d5cd4e7 | ||
|
|
fbb9e9328b | ||
|
|
9824499396 | ||
|
|
59f66933cd | ||
|
|
c1aa63c0bb | ||
|
|
e4a6e52b81 | ||
|
|
06307be15d | ||
|
|
79d3353081 | ||
|
|
f9589f7b64 | ||
|
|
d132c502e6 | ||
|
|
3b30c93f73 | ||
|
|
c0c859ce99 | ||
|
|
22f338d74d | ||
|
|
9919269ed0 | ||
|
|
87596714bf | ||
|
|
296ac5c476 | ||
|
|
ad21d5cac4 | ||
|
|
2559ec8bdb | ||
|
|
207f153ec1 | ||
|
|
3a4011585f | ||
|
|
57f66a455a | ||
|
|
e41fd52e8c | ||
|
|
08f6b5f4ea | ||
|
|
d13e17cf51 | ||
|
|
f1f6109255 | ||
|
|
87b8dc5afb | ||
|
|
fc965c1dc5 | ||
|
|
a1bd54e4ea | ||
|
|
36cceeb10e | ||
|
|
3e71a50403 | ||
|
|
98209e92ee | ||
|
|
1bea7e6985 | ||
|
|
1ba219e0da | ||
|
|
a8e3effb6c | ||
|
|
ca46f4fe2a | ||
|
|
5130f5707f | ||
|
|
6607478b23 | ||
|
|
8eafbd05ca | ||
|
|
de0d19ca09 | ||
|
|
d96869ff66 | ||
|
|
b57a84d065 | ||
|
|
c89827b9f2 | ||
|
|
062a0e3e68 | ||
|
|
a2da5a691a | ||
|
|
afe7966683 | ||
|
|
3ebfb881c9 | ||
|
|
9273e11f21 | ||
|
|
6967f3070e | ||
|
|
a0c6758202 | ||
|
|
80d165475b | ||
|
|
aa6a67044f | ||
|
|
b55a4f805f | ||
|
|
d01f08e96f | ||
|
|
e1f2254fc2 | ||
|
|
f825b4979b | ||
|
|
3d70727021 | ||
|
|
7d59b2e350 | ||
|
|
d9992558fc | ||
|
|
d1f71b0575 | ||
|
|
de6b41e318 | ||
|
|
8d1903fed3 | ||
|
|
13eac944ae | ||
|
|
d8ecca5ebd | ||
|
|
9bbf14d0f6 | ||
|
|
c42d966a40 | ||
|
|
3dc0da9339 | ||
|
|
11ec6aeafb | ||
|
|
9d373d83ac | ||
|
|
221797c609 | ||
|
|
78a027e128 | ||
|
|
488bbd2aeb | ||
|
|
312891daa6 | ||
|
|
fe415e3ff8 | ||
|
|
ff35c17ecf | ||
|
|
9ab83083d1 | ||
|
|
756db2131f | ||
|
|
cb700208e8 | ||
|
|
333a9ad7fa | ||
|
|
5c0feb2877 | ||
|
|
5f17caa156 | ||
|
|
98bf5fc9be | ||
|
|
eb462582af | ||
|
|
9e62a31b63 | ||
|
|
2e33d9b35e | ||
|
|
dc563e4954 | ||
|
|
40254b64e5 | ||
|
|
6e7547244b | ||
|
|
333ec8ba5a | ||
|
|
dcaeef7c10 | ||
|
|
8a2e6a8d51 | ||
|
|
74d536314f | ||
|
|
ceb016514b | ||
|
|
e90f876b34 | ||
|
|
c68a89b4a7 | ||
|
|
1f0d06641a | ||
|
|
a63b34c685 | ||
|
|
522d59e844 | ||
|
|
4c62cd451a |
@@ -1,7 +1,4 @@
|
||||
[run]
|
||||
omit =
|
||||
omit =
|
||||
# standlonetemplate is read dynamically and tested by test_genscript
|
||||
*standalonetemplate.py
|
||||
# oldinterpret could be removed, as it is no longer used in py26+
|
||||
*oldinterpret.py
|
||||
vendored_packages
|
||||
|
||||
19
.github/PULL_REQUEST_TEMPLATE.md
vendored
19
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,15 +1,14 @@
|
||||
Thanks for submitting a PR, your contribution is really appreciated!
|
||||
|
||||
Here's a quick checklist that should be present in PRs:
|
||||
Here's a quick checklist that should be present in PRs (you can delete this text from the final description, this is
|
||||
just a guideline):
|
||||
|
||||
- [ ] Add a new news fragment into the changelog folder
|
||||
* name it `$issue_id.$type` for example (588.bug)
|
||||
* if you don't have an issue_id change it to the pr id after creating the pr
|
||||
* ensure type is one of `removal`, `feature`, `bugfix`, `vendor`, `doc` or `trivial`
|
||||
* Make sure to use full sentences with correct case and punctuation, for example: "Fix issue with non-ascii contents in doctest text files."
|
||||
- [ ] Target: for `bugfix`, `vendor`, `doc` or `trivial` fixes, target `master`; for removals or features target `features`;
|
||||
- [ ] Make sure to include reasonable tests for your change if necessary
|
||||
- [ ] Create a new changelog file in the `changelog` folder, with a name like `<ISSUE NUMBER>.<TYPE>.rst`. See [changelog/README.rst](/changelog/README.rst) for details.
|
||||
- [ ] Target the `master` branch for bug fixes, documentation updates and trivial changes.
|
||||
- [ ] Target the `features` branch for new features and removals/deprecations.
|
||||
- [ ] Include documentation when adding new features.
|
||||
- [ ] Include new tests or update existing tests when applicable.
|
||||
|
||||
Unless your change is a trivial or a documentation fix (e.g., a typo or reword of a small section) please:
|
||||
Unless your change is trivial or a small documentation fix (e.g., a typo or reword of a small section) please:
|
||||
|
||||
- [ ] Add yourself to `AUTHORS`, in alphabetical order;
|
||||
- [ ] Add yourself to `AUTHORS` in alphabetical order;
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -19,7 +19,7 @@ include/
|
||||
.hypothesis/
|
||||
|
||||
# autogenerated
|
||||
_pytest/_version.py
|
||||
src/_pytest/_version.py
|
||||
# setuptools
|
||||
.eggs/
|
||||
|
||||
@@ -33,6 +33,7 @@ env/
|
||||
3rdparty/
|
||||
.tox
|
||||
.cache
|
||||
.pytest_cache
|
||||
.coverage
|
||||
.ropeproject
|
||||
.idea
|
||||
|
||||
36
.pre-commit-config.yaml
Normal file
36
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,36 @@
|
||||
exclude: doc/en/example/py2py3/test_py2.py
|
||||
repos:
|
||||
- repo: https://github.com/ambv/black
|
||||
rev: 18.4a4
|
||||
hooks:
|
||||
- id: black
|
||||
args: [--safe, --quiet]
|
||||
language_version: python3.6
|
||||
- repo: https://github.com/asottile/blacken-docs
|
||||
rev: v0.1.1
|
||||
hooks:
|
||||
- id: blacken-docs
|
||||
additional_dependencies: [black==18.5b1]
|
||||
language_version: python3.6
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v1.2.3
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: debug-statements
|
||||
exclude: _pytest/debugging.py
|
||||
- id: flake8
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v1.2.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: rst
|
||||
name: rst
|
||||
entry: rst-lint --encoding utf-8
|
||||
files: ^(CHANGELOG.rst|HOWTORELEASE.rst|README.rst|changelog/.*)$
|
||||
language: python
|
||||
additional_dependencies: [pygments, restructuredtext_lint]
|
||||
python_version: python3.6
|
||||
47
.travis.yml
47
.travis.yml
@@ -1,17 +1,19 @@
|
||||
sudo: false
|
||||
language: python
|
||||
stages:
|
||||
- linting
|
||||
- test
|
||||
- deploy
|
||||
python:
|
||||
- '3.6'
|
||||
# command to install dependencies
|
||||
install:
|
||||
- pip install --upgrade --pre tox
|
||||
# # command to run tests
|
||||
env:
|
||||
matrix:
|
||||
# coveralls is not listed in tox's envlist, but should run in travis
|
||||
- TOXENV=coveralls
|
||||
# note: please use "tox --listenvs" to populate the build matrix below
|
||||
- TOXENV=linting
|
||||
# please remove the linting env in all cases
|
||||
- TOXENV=py27
|
||||
- TOXENV=py34
|
||||
- TOXENV=py36
|
||||
@@ -19,20 +21,18 @@ env:
|
||||
- TOXENV=py27-xdist
|
||||
- TOXENV=py27-trial
|
||||
- TOXENV=py27-numpy
|
||||
- TOXENV=py27-pluggymaster
|
||||
- TOXENV=py36-pexpect
|
||||
- TOXENV=py36-xdist
|
||||
- TOXENV=py36-trial
|
||||
- TOXENV=py36-numpy
|
||||
- TOXENV=py36-pluggymaster
|
||||
- TOXENV=py27-nobyte
|
||||
- TOXENV=doctesting
|
||||
- TOXENV=docs
|
||||
|
||||
matrix:
|
||||
jobs:
|
||||
include:
|
||||
- env: TOXENV=py26
|
||||
python: '2.6'
|
||||
- env: TOXENV=py33
|
||||
python: '3.3'
|
||||
- env: TOXENV=pypy
|
||||
python: 'pypy-5.4'
|
||||
- env: TOXENV=py35
|
||||
@@ -41,9 +41,30 @@ matrix:
|
||||
python: '3.5'
|
||||
- env: TOXENV=py37
|
||||
python: 'nightly'
|
||||
allow_failures:
|
||||
- env: TOXENV=py37
|
||||
python: 'nightly'
|
||||
|
||||
- stage: deploy
|
||||
python: '3.6'
|
||||
env:
|
||||
install: pip install -U setuptools setuptools_scm
|
||||
script: skip
|
||||
deploy:
|
||||
provider: pypi
|
||||
user: nicoddemus
|
||||
distributions: sdist bdist_wheel
|
||||
skip_upload_docs: true
|
||||
password:
|
||||
secure: xanTgTUu6XDQVqB/0bwJQXoDMnU5tkwZc5koz6mBkkqZhKdNOi2CLoC1XhiSZ+ah24l4V1E0GAqY5kBBcy9d7NVe4WNg4tD095LsHw+CRU6/HCVIFfyk2IZ+FPAlguesCcUiJSXOrlBF+Wj68wEvLoK7EoRFbJeiZ/f91Ww1sbtDlqXABWGHrmhPJL5Wva7o7+wG7JwJowqdZg1pbQExsCc7b53w4v2RBu3D6TJaTAzHiVsW+nUSI67vKI/uf+cR/OixsTfy37wlHgSwihYmrYLFls3V0bSpahCim3bCgMaFZx8S8xrdgJ++PzBCof2HeflFKvW+VCkoYzGEG4NrTWJoNz6ni4red9GdvfjGH3YCjAKS56h9x58zp2E5rpsb/kVq5/45xzV+dq6JRuhQ1nJWjBC6fSKAc/bfwnuFK3EBxNLkvBssLHvsNjj5XG++cB8DdS9wVGUqjpoK4puaXUWFqy4q3S9F86HEsKNgExtieA9qNx+pCIZVs6JCXZNjr0I5eVNzqJIyggNgJG6RyravsU35t9Zd9doL5g4Y7UKmAGTn1Sz24HQ4sMQgXdm2SyD8gEK5je4tlhUvfGtDvMSlstq71kIn9nRpFnqB6MFlbYSEAZmo8dGbCquoUc++6Rum208wcVbrzzVtGlXB/Ow9AbFMYeAGA0+N/K1e59c=
|
||||
on:
|
||||
tags: true
|
||||
repo: pytest-dev/pytest
|
||||
- stage: linting
|
||||
python: '3.6'
|
||||
env:
|
||||
install:
|
||||
- pip install pre-commit
|
||||
- pre-commit install-hooks
|
||||
script:
|
||||
- pre-commit run --all-files
|
||||
|
||||
script: tox --recreate
|
||||
|
||||
@@ -56,3 +77,7 @@ notifications:
|
||||
skip_join: true
|
||||
email:
|
||||
- pytest-commit@python.org
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.cache/pip
|
||||
- $HOME/.cache/pre-commit
|
||||
|
||||
32
AUTHORS
32
AUTHORS
@@ -3,21 +3,27 @@ merlinux GmbH, Germany, office at merlinux eu
|
||||
|
||||
Contributors include::
|
||||
|
||||
Aaron Coleman
|
||||
Abdeali JK
|
||||
Abhijeet Kasurde
|
||||
Ahn Ki-Wook
|
||||
Alan Velasco
|
||||
Alexander Johnson
|
||||
Alexei Kozlenok
|
||||
Anatoly Bubenkoff
|
||||
Anders Hovmöller
|
||||
Andras Tim
|
||||
Andreas Zeidler
|
||||
Andrzej Ostrowski
|
||||
Andy Freeland
|
||||
Anthon van der Neut
|
||||
Anthony Shaw
|
||||
Anthony Sottile
|
||||
Antony Lee
|
||||
Armin Rigo
|
||||
Aron Coyle
|
||||
Aron Curzon
|
||||
Aviral Verma
|
||||
Aviv Palivoda
|
||||
Barney Gale
|
||||
Ben Webb
|
||||
@@ -25,11 +31,14 @@ Benjamin Peterson
|
||||
Bernard Pratz
|
||||
Bob Ippolito
|
||||
Brian Dorsey
|
||||
Brian Maissy
|
||||
Brian Okken
|
||||
Brianna Laugher
|
||||
Bruno Oliveira
|
||||
Cal Leeming
|
||||
Carl Friedrich Bolz
|
||||
Carlos Jenkins
|
||||
Ceridwen
|
||||
Charles Cloud
|
||||
Charnjit SiNGH (CCSJ)
|
||||
Chris Lamb
|
||||
@@ -37,6 +46,7 @@ Christian Boelsen
|
||||
Christian Theunert
|
||||
Christian Tismer
|
||||
Christopher Gilling
|
||||
Cyrus Maden
|
||||
Daniel Grana
|
||||
Daniel Hahler
|
||||
Daniel Nuri
|
||||
@@ -65,6 +75,7 @@ Feng Ma
|
||||
Florian Bruhin
|
||||
Floris Bruynooghe
|
||||
Gabriel Reis
|
||||
George Kussumoto
|
||||
Georgy Dyuldin
|
||||
Graham Horler
|
||||
Greg Price
|
||||
@@ -72,27 +83,35 @@ Grig Gheorghiu
|
||||
Grigorii Eremeev (budulianin)
|
||||
Guido Wesdorp
|
||||
Harald Armin Massa
|
||||
Henk-Jaap Wagenaar
|
||||
Hugo van Kemenade
|
||||
Hui Wang (coldnight)
|
||||
Ian Bicking
|
||||
Ian Lesperance
|
||||
Jaap Broekhuizen
|
||||
Jan Balster
|
||||
Janne Vanhala
|
||||
Jason R. Coombs
|
||||
Javier Domingo Cansino
|
||||
Javier Romero
|
||||
Jeff Rackauckas
|
||||
Jeff Widman
|
||||
John Eddie Ayson
|
||||
John Towler
|
||||
Jon Sonesen
|
||||
Jonas Obrist
|
||||
Jordan Guymon
|
||||
Jordan Moldow
|
||||
Jordan Speicher
|
||||
Joshua Bronson
|
||||
Jurko Gospodnetić
|
||||
Justyna Janczyszyn
|
||||
Kale Kundert
|
||||
Katarzyna Jachim
|
||||
Katerina Koukiou
|
||||
Kevin Cox
|
||||
Kodi B. Arfer
|
||||
Kostis Anagnostopoulos
|
||||
Lawrence Mitchell
|
||||
Lee Kamentsky
|
||||
Lev Maximov
|
||||
@@ -118,6 +137,7 @@ Matt Bachmann
|
||||
Matt Duck
|
||||
Matt Williams
|
||||
Matthias Hafner
|
||||
Maxim Filipenko
|
||||
mbyt
|
||||
Michael Aquilina
|
||||
Michael Birtwell
|
||||
@@ -126,22 +146,26 @@ Michael Seifert
|
||||
Michal Wajszczuk
|
||||
Mihai Capotă
|
||||
Mike Lundy
|
||||
Miro Hrončok
|
||||
Nathaniel Waisbrot
|
||||
Ned Batchelder
|
||||
Neven Mundar
|
||||
Nicolas Delaby
|
||||
Oleg Pidsadnyi
|
||||
Oleg Sushchenko
|
||||
Oliver Bestwalter
|
||||
Omar Kohl
|
||||
Omer Hadari
|
||||
Patrick Hayes
|
||||
Paweł Adamczak
|
||||
Pedro Algarvio
|
||||
Pieter Mulder
|
||||
Piotr Banaszkiewicz
|
||||
Punyashloka Biswal
|
||||
Quentin Pradet
|
||||
Ralf Schmitt
|
||||
Ran Benita
|
||||
Raphael Castaneda
|
||||
Raphael Pierzina
|
||||
Raquel Alegre
|
||||
Ravi Chandra
|
||||
@@ -152,6 +176,7 @@ Ronny Pfannschmidt
|
||||
Ross Lawley
|
||||
Russel Winder
|
||||
Ryan Wooden
|
||||
Samuel Dion-Girardeau
|
||||
Samuele Pedroni
|
||||
Segev Finer
|
||||
Simon Gomizelj
|
||||
@@ -162,19 +187,26 @@ Stefan Zimmermann
|
||||
Stefano Taschini
|
||||
Steffen Allner
|
||||
Stephan Obermann
|
||||
Tarcisio Fischer
|
||||
Tareq Alayan
|
||||
Ted Xiao
|
||||
Thomas Grainger
|
||||
Thomas Hisch
|
||||
Tim Strazny
|
||||
Tom Dalton
|
||||
Tom Viner
|
||||
Trevor Bekolay
|
||||
Tyler Goodlet
|
||||
Tzu-ping Chung
|
||||
Vasily Kuznetsov
|
||||
Victor Uriarte
|
||||
Vidar T. Fauske
|
||||
Vitaly Lashmanov
|
||||
Vlad Dragos
|
||||
William Lee
|
||||
Wouter van Ackooy
|
||||
Xuan Luong
|
||||
Xuecong Liao
|
||||
Zoltán Máté
|
||||
Roland Puntaier
|
||||
Allan Feldman
|
||||
|
||||
861
CHANGELOG.rst
861
CHANGELOG.rst
@@ -1,4 +1,4 @@
|
||||
..
|
||||
..
|
||||
You should *NOT* be adding new change log entries to this file, this
|
||||
file is managed by towncrier. You *may* edit previous change logs to
|
||||
fix problems like typo corrections or such.
|
||||
@@ -8,26 +8,859 @@
|
||||
|
||||
.. towncrier release notes start
|
||||
|
||||
Pytest 3.6.1 (2018-06-05)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Fixed a bug where stdout and stderr were logged twice by junitxml when a test
|
||||
was marked xfail. (`#3491
|
||||
<https://github.com/pytest-dev/pytest/issues/3491>`_)
|
||||
|
||||
- Fix ``usefixtures`` mark applyed to unittest tests by correctly instantiating
|
||||
``FixtureInfo``. (`#3498
|
||||
<https://github.com/pytest-dev/pytest/issues/3498>`_)
|
||||
|
||||
- Fix assertion rewriter compatibility with libraries that monkey patch
|
||||
``file`` objects. (`#3503
|
||||
<https://github.com/pytest-dev/pytest/issues/3503>`_)
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- Added a section on how to use fixtures as factories to the fixture
|
||||
documentation. (`#3461 <https://github.com/pytest-dev/pytest/issues/3461>`_)
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- Enable caching for pip/pre-commit in order to reduce build time on
|
||||
travis/appveyor. (`#3502
|
||||
<https://github.com/pytest-dev/pytest/issues/3502>`_)
|
||||
|
||||
- Switch pytest to the src/ layout as we already suggested it for good practice
|
||||
- now we implement it as well. (`#3513
|
||||
<https://github.com/pytest-dev/pytest/issues/3513>`_)
|
||||
|
||||
- Fix if in tests to support 3.7.0b5, where a docstring handling in AST got
|
||||
reverted. (`#3530 <https://github.com/pytest-dev/pytest/issues/3530>`_)
|
||||
|
||||
- Remove some python2.5 compatibility code. (`#3629
|
||||
<https://github.com/pytest-dev/pytest/issues/3629>`_)
|
||||
|
||||
|
||||
Pytest 3.6.0 (2018-05-23)
|
||||
=========================
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Revamp the internals of the ``pytest.mark`` implementation with correct per
|
||||
node handling which fixes a number of long standing bugs caused by the old
|
||||
design. This introduces new ``Node.iter_markers(name)`` and
|
||||
``Node.get_closest_mark(name)`` APIs. Users are **strongly encouraged** to
|
||||
read the `reasons for the revamp in the docs
|
||||
<https://docs.pytest.org/en/latest/mark.html#marker-revamp-and-iteration>`_,
|
||||
or jump over to details about `updating existing code to use the new APIs
|
||||
<https://docs.pytest.org/en/latest/mark.html#updating-code>`_. (`#3317
|
||||
<https://github.com/pytest-dev/pytest/issues/3317>`_)
|
||||
|
||||
- Now when ``@pytest.fixture`` is applied more than once to the same function a
|
||||
``ValueError`` is raised. This buggy behavior would cause surprising problems
|
||||
and if was working for a test suite it was mostly by accident. (`#2334
|
||||
<https://github.com/pytest-dev/pytest/issues/2334>`_)
|
||||
|
||||
- Support for Python 3.7's builtin ``breakpoint()`` method, see `Using the
|
||||
builtin breakpoint function
|
||||
<https://docs.pytest.org/en/latest/usage.html#breakpoint-builtin>`_ for
|
||||
details. (`#3180 <https://github.com/pytest-dev/pytest/issues/3180>`_)
|
||||
|
||||
- ``monkeypatch`` now supports a ``context()`` function which acts as a context
|
||||
manager which undoes all patching done within the ``with`` block. (`#3290
|
||||
<https://github.com/pytest-dev/pytest/issues/3290>`_)
|
||||
|
||||
- The ``--pdb`` option now causes KeyboardInterrupt to enter the debugger,
|
||||
instead of stopping the test session. On python 2.7, hitting CTRL+C again
|
||||
exits the debugger. On python 3.2 and higher, use CTRL+D. (`#3299
|
||||
<https://github.com/pytest-dev/pytest/issues/3299>`_)
|
||||
|
||||
- pytest not longer changes the log level of the root logger when the
|
||||
``log-level`` parameter has greater numeric value than that of the level of
|
||||
the root logger, which makes it play better with custom logging configuration
|
||||
in user code. (`#3307 <https://github.com/pytest-dev/pytest/issues/3307>`_)
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- A rare race-condition which might result in corrupted ``.pyc`` files on
|
||||
Windows has been hopefully solved. (`#3008
|
||||
<https://github.com/pytest-dev/pytest/issues/3008>`_)
|
||||
|
||||
- Also use iter_marker for discovering the marks applying for marker
|
||||
expressions from the cli to avoid the bad data from the legacy mark storage.
|
||||
(`#3441 <https://github.com/pytest-dev/pytest/issues/3441>`_)
|
||||
|
||||
- When showing diffs of failed assertions where the contents contain only
|
||||
whitespace, escape them using ``repr()`` first to make it easy to spot the
|
||||
differences. (`#3443 <https://github.com/pytest-dev/pytest/issues/3443>`_)
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- Change documentation copyright year to a range which auto-updates itself each
|
||||
time it is published. (`#3303
|
||||
<https://github.com/pytest-dev/pytest/issues/3303>`_)
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- ``pytest`` now depends on the `python-atomicwrites
|
||||
<https://github.com/untitaker/python-atomicwrites>`_ library. (`#3008
|
||||
<https://github.com/pytest-dev/pytest/issues/3008>`_)
|
||||
|
||||
- Update all pypi.python.org URLs to pypi.org. (`#3431
|
||||
<https://github.com/pytest-dev/pytest/issues/3431>`_)
|
||||
|
||||
- Detect `pytest_` prefixed hooks using the internal plugin manager since
|
||||
``pluggy`` is deprecating the ``implprefix`` argument to ``PluginManager``.
|
||||
(`#3487 <https://github.com/pytest-dev/pytest/issues/3487>`_)
|
||||
|
||||
- Import ``Mapping`` and ``Sequence`` from ``_pytest.compat`` instead of
|
||||
directly from ``collections`` in ``python_api.py::approx``. Add ``Mapping``
|
||||
to ``_pytest.compat``, import it from ``collections`` on python 2, but from
|
||||
``collections.abc`` on Python 3 to avoid a ``DeprecationWarning`` on Python
|
||||
3.7 or newer. (`#3497 <https://github.com/pytest-dev/pytest/issues/3497>`_)
|
||||
|
||||
|
||||
Pytest 3.5.1 (2018-04-23)
|
||||
=========================
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Reset ``sys.last_type``, ``sys.last_value`` and ``sys.last_traceback`` before
|
||||
each test executes. Those attributes are added by pytest during the test run
|
||||
to aid debugging, but were never reset so they would create a leaking
|
||||
reference to the last failing test's frame which in turn could never be
|
||||
reclaimed by the garbage collector. (`#2798
|
||||
<https://github.com/pytest-dev/pytest/issues/2798>`_)
|
||||
|
||||
- ``pytest.raises`` now raises ``TypeError`` when receiving an unknown keyword
|
||||
argument. (`#3348 <https://github.com/pytest-dev/pytest/issues/3348>`_)
|
||||
|
||||
- ``pytest.raises`` now works with exception classes that look like iterables.
|
||||
(`#3372 <https://github.com/pytest-dev/pytest/issues/3372>`_)
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- Fix typo in ``caplog`` fixture documentation, which incorrectly identified
|
||||
certain attributes as methods. (`#3406
|
||||
<https://github.com/pytest-dev/pytest/issues/3406>`_)
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- Added a more indicative error message when parametrizing a function whose
|
||||
argument takes a default value. (`#3221
|
||||
<https://github.com/pytest-dev/pytest/issues/3221>`_)
|
||||
|
||||
- Remove internal ``_pytest.terminal.flatten`` function in favor of
|
||||
``more_itertools.collapse``. (`#3330
|
||||
<https://github.com/pytest-dev/pytest/issues/3330>`_)
|
||||
|
||||
- Import some modules from ``collections.abc`` instead of ``collections`` as
|
||||
the former modules trigger ``DeprecationWarning`` in Python 3.7. (`#3339
|
||||
<https://github.com/pytest-dev/pytest/issues/3339>`_)
|
||||
|
||||
- record_property is no longer experimental, removing the warnings was
|
||||
forgotten. (`#3360 <https://github.com/pytest-dev/pytest/issues/3360>`_)
|
||||
|
||||
- Mention in documentation and CLI help that fixtures with leading ``_`` are
|
||||
printed by ``pytest --fixtures`` only if the ``-v`` option is added. (`#3398
|
||||
<https://github.com/pytest-dev/pytest/issues/3398>`_)
|
||||
|
||||
|
||||
Pytest 3.5.0 (2018-03-21)
|
||||
=========================
|
||||
|
||||
Deprecations and Removals
|
||||
-------------------------
|
||||
|
||||
- ``record_xml_property`` fixture is now deprecated in favor of the more
|
||||
generic ``record_property``. (`#2770
|
||||
<https://github.com/pytest-dev/pytest/issues/2770>`_)
|
||||
|
||||
- Defining ``pytest_plugins`` is now deprecated in non-top-level conftest.py
|
||||
files, because they "leak" to the entire directory tree. (`#3084
|
||||
<https://github.com/pytest-dev/pytest/issues/3084>`_)
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- New ``--show-capture`` command-line option that allows to specify how to
|
||||
display captured output when tests fail: ``no``, ``stdout``, ``stderr``,
|
||||
``log`` or ``all`` (the default). (`#1478
|
||||
<https://github.com/pytest-dev/pytest/issues/1478>`_)
|
||||
|
||||
- New ``--rootdir`` command-line option to override the rules for discovering
|
||||
the root directory. See `customize
|
||||
<https://docs.pytest.org/en/latest/customize.html>`_ in the documentation for
|
||||
details. (`#1642 <https://github.com/pytest-dev/pytest/issues/1642>`_)
|
||||
|
||||
- Fixtures are now instantiated based on their scopes, with higher-scoped
|
||||
fixtures (such as ``session``) being instantiated first than lower-scoped
|
||||
fixtures (such as ``function``). The relative order of fixtures of the same
|
||||
scope is kept unchanged, based in their declaration order and their
|
||||
dependencies. (`#2405 <https://github.com/pytest-dev/pytest/issues/2405>`_)
|
||||
|
||||
- ``record_xml_property`` renamed to ``record_property`` and is now compatible
|
||||
with xdist, markers and any reporter. ``record_xml_property`` name is now
|
||||
deprecated. (`#2770 <https://github.com/pytest-dev/pytest/issues/2770>`_)
|
||||
|
||||
- New ``--nf``, ``--new-first`` options: run new tests first followed by the
|
||||
rest of the tests, in both cases tests are also sorted by the file modified
|
||||
time, with more recent files coming first. (`#3034
|
||||
<https://github.com/pytest-dev/pytest/issues/3034>`_)
|
||||
|
||||
- New ``--last-failed-no-failures`` command-line option that allows to specify
|
||||
the behavior of the cache plugin's ```--last-failed`` feature when no tests
|
||||
failed in the last run (or no cache was found): ``none`` or ``all`` (the
|
||||
default). (`#3139 <https://github.com/pytest-dev/pytest/issues/3139>`_)
|
||||
|
||||
- New ``--doctest-continue-on-failure`` command-line option to enable doctests
|
||||
to show multiple failures for each snippet, instead of stopping at the first
|
||||
failure. (`#3149 <https://github.com/pytest-dev/pytest/issues/3149>`_)
|
||||
|
||||
- Captured log messages are added to the ``<system-out>`` tag in the generated
|
||||
junit xml file if the ``junit_logging`` ini option is set to ``system-out``.
|
||||
If the value of this ini option is ``system-err``, the logs are written to
|
||||
``<system-err>``. The default value for ``junit_logging`` is ``no``, meaning
|
||||
captured logs are not written to the output file. (`#3156
|
||||
<https://github.com/pytest-dev/pytest/issues/3156>`_)
|
||||
|
||||
- Allow the logging plugin to handle ``pytest_runtest_logstart`` and
|
||||
``pytest_runtest_logfinish`` hooks when live logs are enabled. (`#3189
|
||||
<https://github.com/pytest-dev/pytest/issues/3189>`_)
|
||||
|
||||
- Passing `--log-cli-level` in the command-line now automatically activates
|
||||
live logging. (`#3190 <https://github.com/pytest-dev/pytest/issues/3190>`_)
|
||||
|
||||
- Add command line option ``--deselect`` to allow deselection of individual
|
||||
tests at collection time. (`#3198
|
||||
<https://github.com/pytest-dev/pytest/issues/3198>`_)
|
||||
|
||||
- Captured logs are printed before entering pdb. (`#3204
|
||||
<https://github.com/pytest-dev/pytest/issues/3204>`_)
|
||||
|
||||
- Deselected item count is now shown before tests are run, e.g. ``collected X
|
||||
items / Y deselected``. (`#3213
|
||||
<https://github.com/pytest-dev/pytest/issues/3213>`_)
|
||||
|
||||
- The builtin module ``platform`` is now available for use in expressions in
|
||||
``pytest.mark``. (`#3236
|
||||
<https://github.com/pytest-dev/pytest/issues/3236>`_)
|
||||
|
||||
- The *short test summary info* section now is displayed after tracebacks and
|
||||
warnings in the terminal. (`#3255
|
||||
<https://github.com/pytest-dev/pytest/issues/3255>`_)
|
||||
|
||||
- New ``--verbosity`` flag to set verbosity level explicitly. (`#3296
|
||||
<https://github.com/pytest-dev/pytest/issues/3296>`_)
|
||||
|
||||
- ``pytest.approx`` now accepts comparing a numpy array with a scalar. (`#3312
|
||||
<https://github.com/pytest-dev/pytest/issues/3312>`_)
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Suppress ``IOError`` when closing the temporary file used for capturing
|
||||
streams in Python 2.7. (`#2370
|
||||
<https://github.com/pytest-dev/pytest/issues/2370>`_)
|
||||
|
||||
- Fixed ``clear()`` method on ``caplog`` fixture which cleared ``records``, but
|
||||
not the ``text`` property. (`#3297
|
||||
<https://github.com/pytest-dev/pytest/issues/3297>`_)
|
||||
|
||||
- During test collection, when stdin is not allowed to be read, the
|
||||
``DontReadFromStdin`` object still allow itself to be iterable and resolved
|
||||
to an iterator without crashing. (`#3314
|
||||
<https://github.com/pytest-dev/pytest/issues/3314>`_)
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- Added a `reference <https://docs.pytest.org/en/latest/reference.html>`_ page
|
||||
to the docs. (`#1713 <https://github.com/pytest-dev/pytest/issues/1713>`_)
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- Change minimum requirement of ``attrs`` to ``17.4.0``. (`#3228
|
||||
<https://github.com/pytest-dev/pytest/issues/3228>`_)
|
||||
|
||||
- Renamed example directories so all tests pass when ran from the base
|
||||
directory. (`#3245 <https://github.com/pytest-dev/pytest/issues/3245>`_)
|
||||
|
||||
- Internal ``mark.py`` module has been turned into a package. (`#3250
|
||||
<https://github.com/pytest-dev/pytest/issues/3250>`_)
|
||||
|
||||
- ``pytest`` now depends on the `more-itertools
|
||||
<https://github.com/erikrose/more-itertools>`_ package. (`#3265
|
||||
<https://github.com/pytest-dev/pytest/issues/3265>`_)
|
||||
|
||||
- Added warning when ``[pytest]`` section is used in a ``.cfg`` file passed
|
||||
with ``-c`` (`#3268 <https://github.com/pytest-dev/pytest/issues/3268>`_)
|
||||
|
||||
- ``nodeids`` can now be passed explicitly to ``FSCollector`` and ``Node``
|
||||
constructors. (`#3291 <https://github.com/pytest-dev/pytest/issues/3291>`_)
|
||||
|
||||
- Internal refactoring of ``FormattedExcinfo`` to use ``attrs`` facilities and
|
||||
remove old support code for legacy Python versions. (`#3292
|
||||
<https://github.com/pytest-dev/pytest/issues/3292>`_)
|
||||
|
||||
- Refactoring to unify how verbosity is handled internally. (`#3296
|
||||
<https://github.com/pytest-dev/pytest/issues/3296>`_)
|
||||
|
||||
- Internal refactoring to better integrate with argparse. (`#3304
|
||||
<https://github.com/pytest-dev/pytest/issues/3304>`_)
|
||||
|
||||
- Fix a python example when calling a fixture in doc/en/usage.rst (`#3308
|
||||
<https://github.com/pytest-dev/pytest/issues/3308>`_)
|
||||
|
||||
|
||||
Pytest 3.4.2 (2018-03-04)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Removed progress information when capture option is ``no``. (`#3203
|
||||
<https://github.com/pytest-dev/pytest/issues/3203>`_)
|
||||
|
||||
- Refactor check of bindir from ``exists`` to ``isdir``. (`#3241
|
||||
<https://github.com/pytest-dev/pytest/issues/3241>`_)
|
||||
|
||||
- Fix ``TypeError`` issue when using ``approx`` with a ``Decimal`` value.
|
||||
(`#3247 <https://github.com/pytest-dev/pytest/issues/3247>`_)
|
||||
|
||||
- Fix reference cycle generated when using the ``request`` fixture. (`#3249
|
||||
<https://github.com/pytest-dev/pytest/issues/3249>`_)
|
||||
|
||||
- ``[tool:pytest]`` sections in ``*.cfg`` files passed by the ``-c`` option are
|
||||
now properly recognized. (`#3260
|
||||
<https://github.com/pytest-dev/pytest/issues/3260>`_)
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- Add logging plugin to plugins list. (`#3209
|
||||
<https://github.com/pytest-dev/pytest/issues/3209>`_)
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- Fix minor typo in fixture.rst (`#3259
|
||||
<https://github.com/pytest-dev/pytest/issues/3259>`_)
|
||||
|
||||
|
||||
Pytest 3.4.1 (2018-02-20)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Move import of ``doctest.UnexpectedException`` to top-level to avoid possible
|
||||
errors when using ``--pdb``. (`#1810
|
||||
<https://github.com/pytest-dev/pytest/issues/1810>`_)
|
||||
|
||||
- Added printing of captured stdout/stderr before entering pdb, and improved a
|
||||
test which was giving false negatives about output capturing. (`#3052
|
||||
<https://github.com/pytest-dev/pytest/issues/3052>`_)
|
||||
|
||||
- Fix ordering of tests using parametrized fixtures which can lead to fixtures
|
||||
being created more than necessary. (`#3161
|
||||
<https://github.com/pytest-dev/pytest/issues/3161>`_)
|
||||
|
||||
- Fix bug where logging happening at hooks outside of "test run" hooks would
|
||||
cause an internal error. (`#3184
|
||||
<https://github.com/pytest-dev/pytest/issues/3184>`_)
|
||||
|
||||
- Detect arguments injected by ``unittest.mock.patch`` decorator correctly when
|
||||
pypi ``mock.patch`` is installed and imported. (`#3206
|
||||
<https://github.com/pytest-dev/pytest/issues/3206>`_)
|
||||
|
||||
- Errors shown when a ``pytest.raises()`` with ``match=`` fails are now cleaner
|
||||
on what happened: When no exception was raised, the "matching '...'" part got
|
||||
removed as it falsely implies that an exception was raised but it didn't
|
||||
match. When a wrong exception was raised, it's now thrown (like
|
||||
``pytest.raised()`` without ``match=`` would) instead of complaining about
|
||||
the unmatched text. (`#3222
|
||||
<https://github.com/pytest-dev/pytest/issues/3222>`_)
|
||||
|
||||
- Fixed output capture handling in doctests on macOS. (`#985
|
||||
<https://github.com/pytest-dev/pytest/issues/985>`_)
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- Add Sphinx parameter docs for ``match`` and ``message`` args to
|
||||
``pytest.raises``. (`#3202
|
||||
<https://github.com/pytest-dev/pytest/issues/3202>`_)
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- pytest has changed the publication procedure and is now being published to
|
||||
PyPI directly from Travis. (`#3060
|
||||
<https://github.com/pytest-dev/pytest/issues/3060>`_)
|
||||
|
||||
- Rename ``ParameterSet._for_parameterize()`` to ``_for_parametrize()`` in
|
||||
order to comply with the naming convention. (`#3166
|
||||
<https://github.com/pytest-dev/pytest/issues/3166>`_)
|
||||
|
||||
- Skip failing pdb/doctest test on mac. (`#985
|
||||
<https://github.com/pytest-dev/pytest/issues/985>`_)
|
||||
|
||||
|
||||
Pytest 3.4.0 (2018-01-30)
|
||||
=========================
|
||||
|
||||
Deprecations and Removals
|
||||
-------------------------
|
||||
|
||||
- All pytest classes now subclass ``object`` for better Python 2/3 compatibility.
|
||||
This should not affect user code except in very rare edge cases. (`#2147
|
||||
<https://github.com/pytest-dev/pytest/issues/2147>`_)
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Introduce ``empty_parameter_set_mark`` ini option to select which mark to
|
||||
apply when ``@pytest.mark.parametrize`` is given an empty set of parameters.
|
||||
Valid options are ``skip`` (default) and ``xfail``. Note that it is planned
|
||||
to change the default to ``xfail`` in future releases as this is considered
|
||||
less error prone. (`#2527
|
||||
<https://github.com/pytest-dev/pytest/issues/2527>`_)
|
||||
|
||||
- **Incompatible change**: after community feedback the `logging
|
||||
<https://docs.pytest.org/en/latest/logging.html>`_ functionality has
|
||||
undergone some changes. Please consult the `logging documentation
|
||||
<https://docs.pytest.org/en/latest/logging.html#incompatible-changes-in-pytest-3-4>`_
|
||||
for details. (`#3013 <https://github.com/pytest-dev/pytest/issues/3013>`_)
|
||||
|
||||
- Console output falls back to "classic" mode when capturing is disabled (``-s``),
|
||||
otherwise the output gets garbled to the point of being useless. (`#3038
|
||||
<https://github.com/pytest-dev/pytest/issues/3038>`_)
|
||||
|
||||
- New `pytest_runtest_logfinish
|
||||
<https://docs.pytest.org/en/latest/writing_plugins.html#_pytest.hookspec.pytest_runtest_logfinish>`_
|
||||
hook which is called when a test item has finished executing, analogous to
|
||||
`pytest_runtest_logstart
|
||||
<https://docs.pytest.org/en/latest/writing_plugins.html#_pytest.hookspec.pytest_runtest_start>`_.
|
||||
(`#3101 <https://github.com/pytest-dev/pytest/issues/3101>`_)
|
||||
|
||||
- Improve performance when collecting tests using many fixtures. (`#3107
|
||||
<https://github.com/pytest-dev/pytest/issues/3107>`_)
|
||||
|
||||
- New ``caplog.get_records(when)`` method which provides access to the captured
|
||||
records for the ``"setup"``, ``"call"`` and ``"teardown"``
|
||||
testing stages. (`#3117 <https://github.com/pytest-dev/pytest/issues/3117>`_)
|
||||
|
||||
- New fixture ``record_xml_attribute`` that allows modifying and inserting
|
||||
attributes on the ``<testcase>`` xml node in JUnit reports. (`#3130
|
||||
<https://github.com/pytest-dev/pytest/issues/3130>`_)
|
||||
|
||||
- The default cache directory has been renamed from ``.cache`` to
|
||||
``.pytest_cache`` after community feedback that the name ``.cache`` did not
|
||||
make it clear that it was used by pytest. (`#3138
|
||||
<https://github.com/pytest-dev/pytest/issues/3138>`_)
|
||||
|
||||
- Colorize the levelname column in the live-log output. (`#3142
|
||||
<https://github.com/pytest-dev/pytest/issues/3142>`_)
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Fix hanging pexpect test on MacOS by using flush() instead of wait().
|
||||
(`#2022 <https://github.com/pytest-dev/pytest/issues/2022>`_)
|
||||
|
||||
- Fix restoring Python state after in-process pytest runs with the
|
||||
``pytester`` plugin; this may break tests using multiple inprocess
|
||||
pytest runs if later ones depend on earlier ones leaking global interpreter
|
||||
changes. (`#3016 <https://github.com/pytest-dev/pytest/issues/3016>`_)
|
||||
|
||||
- Fix skipping plugin reporting hook when test aborted before plugin setup
|
||||
hook. (`#3074 <https://github.com/pytest-dev/pytest/issues/3074>`_)
|
||||
|
||||
- Fix progress percentage reported when tests fail during teardown. (`#3088
|
||||
<https://github.com/pytest-dev/pytest/issues/3088>`_)
|
||||
|
||||
- **Incompatible change**: ``-o/--override`` option no longer eats all the
|
||||
remaining options, which can lead to surprising behavior: for example,
|
||||
``pytest -o foo=1 /path/to/test.py`` would fail because ``/path/to/test.py``
|
||||
would be considered as part of the ``-o`` command-line argument. One
|
||||
consequence of this is that now multiple configuration overrides need
|
||||
multiple ``-o`` flags: ``pytest -o foo=1 -o bar=2``. (`#3103
|
||||
<https://github.com/pytest-dev/pytest/issues/3103>`_)
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- Document hooks (defined with ``historic=True``) which cannot be used with
|
||||
``hookwrapper=True``. (`#2423
|
||||
<https://github.com/pytest-dev/pytest/issues/2423>`_)
|
||||
|
||||
- Clarify that warning capturing doesn't change the warning filter by default.
|
||||
(`#2457 <https://github.com/pytest-dev/pytest/issues/2457>`_)
|
||||
|
||||
- Clarify a possible confusion when using pytest_fixture_setup with fixture
|
||||
functions that return None. (`#2698
|
||||
<https://github.com/pytest-dev/pytest/issues/2698>`_)
|
||||
|
||||
- Fix the wording of a sentence on doctest flags used in pytest. (`#3076
|
||||
<https://github.com/pytest-dev/pytest/issues/3076>`_)
|
||||
|
||||
- Prefer ``https://*.readthedocs.io`` over ``http://*.rtfd.org`` for links in
|
||||
the documentation. (`#3092
|
||||
<https://github.com/pytest-dev/pytest/issues/3092>`_)
|
||||
|
||||
- Improve readability (wording, grammar) of Getting Started guide (`#3131
|
||||
<https://github.com/pytest-dev/pytest/issues/3131>`_)
|
||||
|
||||
- Added note that calling pytest.main multiple times from the same process is
|
||||
not recommended because of import caching. (`#3143
|
||||
<https://github.com/pytest-dev/pytest/issues/3143>`_)
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- Show a simple and easy error when keyword expressions trigger a syntax error
|
||||
(for example, ``"-k foo and import"`` will show an error that you can not use
|
||||
the ``import`` keyword in expressions). (`#2953
|
||||
<https://github.com/pytest-dev/pytest/issues/2953>`_)
|
||||
|
||||
- Change parametrized automatic test id generation to use the ``__name__``
|
||||
attribute of functions instead of the fallback argument name plus counter.
|
||||
(`#2976 <https://github.com/pytest-dev/pytest/issues/2976>`_)
|
||||
|
||||
- Replace py.std with stdlib imports. (`#3067
|
||||
<https://github.com/pytest-dev/pytest/issues/3067>`_)
|
||||
|
||||
- Corrected 'you' to 'your' in logging docs. (`#3129
|
||||
<https://github.com/pytest-dev/pytest/issues/3129>`_)
|
||||
|
||||
|
||||
Pytest 3.3.2 (2017-12-25)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- pytester: ignore files used to obtain current user metadata in the fd leak
|
||||
detector. (`#2784 <https://github.com/pytest-dev/pytest/issues/2784>`_)
|
||||
|
||||
- Fix **memory leak** where objects returned by fixtures were never destructed
|
||||
by the garbage collector. (`#2981
|
||||
<https://github.com/pytest-dev/pytest/issues/2981>`_)
|
||||
|
||||
- Fix conversion of pyargs to filename to not convert symlinks on Python 2. (`#2985
|
||||
<https://github.com/pytest-dev/pytest/issues/2985>`_)
|
||||
|
||||
- ``PYTEST_DONT_REWRITE`` is now checked for plugins too rather than only for
|
||||
test modules. (`#2995 <https://github.com/pytest-dev/pytest/issues/2995>`_)
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- Add clarifying note about behavior of multiple parametrized arguments (`#3001
|
||||
<https://github.com/pytest-dev/pytest/issues/3001>`_)
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- Code cleanup. (`#3015 <https://github.com/pytest-dev/pytest/issues/3015>`_,
|
||||
`#3021 <https://github.com/pytest-dev/pytest/issues/3021>`_)
|
||||
|
||||
- Clean up code by replacing imports and references of `_ast` to `ast`. (`#3018
|
||||
<https://github.com/pytest-dev/pytest/issues/3018>`_)
|
||||
|
||||
|
||||
Pytest 3.3.1 (2017-12-05)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Fix issue about ``-p no:<plugin>`` having no effect. (`#2920
|
||||
<https://github.com/pytest-dev/pytest/issues/2920>`_)
|
||||
|
||||
- Fix regression with warnings that contained non-strings in their arguments in
|
||||
Python 2. (`#2956 <https://github.com/pytest-dev/pytest/issues/2956>`_)
|
||||
|
||||
- Always escape null bytes when setting ``PYTEST_CURRENT_TEST``. (`#2957
|
||||
<https://github.com/pytest-dev/pytest/issues/2957>`_)
|
||||
|
||||
- Fix ``ZeroDivisionError`` when using the ``testmon`` plugin when no tests
|
||||
were actually collected. (`#2971
|
||||
<https://github.com/pytest-dev/pytest/issues/2971>`_)
|
||||
|
||||
- Bring back ``TerminalReporter.writer`` as an alias to
|
||||
``TerminalReporter._tw``. This alias was removed by accident in the ``3.3.0``
|
||||
release. (`#2984 <https://github.com/pytest-dev/pytest/issues/2984>`_)
|
||||
|
||||
- The ``pytest-capturelog`` plugin is now also blacklisted, avoiding errors when
|
||||
running pytest with it still installed. (`#3004
|
||||
<https://github.com/pytest-dev/pytest/issues/3004>`_)
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- Fix broken link to plugin ``pytest-localserver``. (`#2963
|
||||
<https://github.com/pytest-dev/pytest/issues/2963>`_)
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- Update github "bugs" link in ``CONTRIBUTING.rst`` (`#2949
|
||||
<https://github.com/pytest-dev/pytest/issues/2949>`_)
|
||||
|
||||
|
||||
Pytest 3.3.0 (2017-11-23)
|
||||
=========================
|
||||
|
||||
Deprecations and Removals
|
||||
-------------------------
|
||||
|
||||
- Pytest no longer supports Python **2.6** and **3.3**. Those Python versions
|
||||
are EOL for some time now and incur maintenance and compatibility costs on
|
||||
the pytest core team, and following up with the rest of the community we
|
||||
decided that they will no longer be supported starting on this version. Users
|
||||
which still require those versions should pin pytest to ``<3.3``. (`#2812
|
||||
<https://github.com/pytest-dev/pytest/issues/2812>`_)
|
||||
|
||||
- Remove internal ``_preloadplugins()`` function. This removal is part of the
|
||||
``pytest_namespace()`` hook deprecation. (`#2636
|
||||
<https://github.com/pytest-dev/pytest/issues/2636>`_)
|
||||
|
||||
- Internally change ``CallSpec2`` to have a list of marks instead of a broken
|
||||
mapping of keywords. This removes the keywords attribute of the internal
|
||||
``CallSpec2`` class. (`#2672
|
||||
<https://github.com/pytest-dev/pytest/issues/2672>`_)
|
||||
|
||||
- Remove ParameterSet.deprecated_arg_dict - its not a public api and the lack
|
||||
of the underscore was a naming error. (`#2675
|
||||
<https://github.com/pytest-dev/pytest/issues/2675>`_)
|
||||
|
||||
- Remove the internal multi-typed attribute ``Node._evalskip`` and replace it
|
||||
with the boolean ``Node._skipped_by_mark``. (`#2767
|
||||
<https://github.com/pytest-dev/pytest/issues/2767>`_)
|
||||
|
||||
- The ``params`` list passed to ``pytest.fixture`` is now for
|
||||
all effects considered immutable and frozen at the moment of the ``pytest.fixture``
|
||||
call. Previously the list could be changed before the first invocation of the fixture
|
||||
allowing for a form of dynamic parametrization (for example, updated from command-line options),
|
||||
but this was an unwanted implementation detail which complicated the internals and prevented
|
||||
some internal cleanup. See issue `#2959 <https://github.com/pytest-dev/pytest/issues/2959>`_
|
||||
for details and a recommended workaround.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- ``pytest_fixture_post_finalizer`` hook can now receive a ``request``
|
||||
argument. (`#2124 <https://github.com/pytest-dev/pytest/issues/2124>`_)
|
||||
|
||||
- Replace the old introspection code in compat.py that determines the available
|
||||
arguments of fixtures with inspect.signature on Python 3 and
|
||||
funcsigs.signature on Python 2. This should respect ``__signature__``
|
||||
declarations on functions. (`#2267
|
||||
<https://github.com/pytest-dev/pytest/issues/2267>`_)
|
||||
|
||||
- Report tests with global ``pytestmark`` variable only once. (`#2549
|
||||
<https://github.com/pytest-dev/pytest/issues/2549>`_)
|
||||
|
||||
- Now pytest displays the total progress percentage while running tests. The
|
||||
previous output style can be set by configuring the ``console_output_style``
|
||||
setting to ``classic``. (`#2657 <https://github.com/pytest-dev/pytest/issues/2657>`_)
|
||||
|
||||
- Match ``warns`` signature to ``raises`` by adding ``match`` keyword. (`#2708
|
||||
<https://github.com/pytest-dev/pytest/issues/2708>`_)
|
||||
|
||||
- Pytest now captures and displays output from the standard ``logging`` module.
|
||||
The user can control the logging level to be captured by specifying options
|
||||
in ``pytest.ini``, the command line and also during individual tests using
|
||||
markers. Also, a ``caplog`` fixture is available that enables users to test
|
||||
the captured log during specific tests (similar to ``capsys`` for example).
|
||||
For more information, please see the `logging docs
|
||||
<https://docs.pytest.org/en/latest/logging.html>`_. This feature was
|
||||
introduced by merging the popular `pytest-catchlog
|
||||
<https://pypi.org/project/pytest-catchlog/>`_ plugin, thanks to `Thomas Hisch
|
||||
<https://github.com/thisch>`_. Be advised that during the merging the
|
||||
backward compatibility interface with the defunct ``pytest-capturelog`` has
|
||||
been dropped. (`#2794 <https://github.com/pytest-dev/pytest/issues/2794>`_)
|
||||
|
||||
- Add ``allow_module_level`` kwarg to ``pytest.skip()``, enabling to skip the
|
||||
whole module. (`#2808 <https://github.com/pytest-dev/pytest/issues/2808>`_)
|
||||
|
||||
- Allow setting ``file_or_dir``, ``-c``, and ``-o`` in PYTEST_ADDOPTS. (`#2824
|
||||
<https://github.com/pytest-dev/pytest/issues/2824>`_)
|
||||
|
||||
- Return stdout/stderr capture results as a ``namedtuple``, so ``out`` and
|
||||
``err`` can be accessed by attribute. (`#2879
|
||||
<https://github.com/pytest-dev/pytest/issues/2879>`_)
|
||||
|
||||
- Add ``capfdbinary``, a version of ``capfd`` which returns bytes from
|
||||
``readouterr()``. (`#2923
|
||||
<https://github.com/pytest-dev/pytest/issues/2923>`_)
|
||||
|
||||
- Add ``capsysbinary`` a version of ``capsys`` which returns bytes from
|
||||
``readouterr()``. (`#2934
|
||||
<https://github.com/pytest-dev/pytest/issues/2934>`_)
|
||||
|
||||
- Implement feature to skip ``setup.py`` files when run with
|
||||
``--doctest-modules``. (`#502
|
||||
<https://github.com/pytest-dev/pytest/issues/502>`_)
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Resume output capturing after ``capsys/capfd.disabled()`` context manager.
|
||||
(`#1993 <https://github.com/pytest-dev/pytest/issues/1993>`_)
|
||||
|
||||
- ``pytest_fixture_setup`` and ``pytest_fixture_post_finalizer`` hooks are now
|
||||
called for all ``conftest.py`` files. (`#2124
|
||||
<https://github.com/pytest-dev/pytest/issues/2124>`_)
|
||||
|
||||
- If an exception happens while loading a plugin, pytest no longer hides the
|
||||
original traceback. In Python 2 it will show the original traceback with a new
|
||||
message that explains in which plugin. In Python 3 it will show 2 canonized
|
||||
exceptions, the original exception while loading the plugin in addition to an
|
||||
exception that pytest throws about loading a plugin. (`#2491
|
||||
<https://github.com/pytest-dev/pytest/issues/2491>`_)
|
||||
|
||||
- ``capsys`` and ``capfd`` can now be used by other fixtures. (`#2709
|
||||
<https://github.com/pytest-dev/pytest/issues/2709>`_)
|
||||
|
||||
- Internal ``pytester`` plugin properly encodes ``bytes`` arguments to
|
||||
``utf-8``. (`#2738 <https://github.com/pytest-dev/pytest/issues/2738>`_)
|
||||
|
||||
- ``testdir`` now uses use the same method used by ``tmpdir`` to create its
|
||||
temporary directory. This changes the final structure of the ``testdir``
|
||||
directory slightly, but should not affect usage in normal scenarios and
|
||||
avoids a number of potential problems. (`#2751
|
||||
<https://github.com/pytest-dev/pytest/issues/2751>`_)
|
||||
|
||||
- Pytest no longer complains about warnings with unicode messages being
|
||||
non-ascii compatible even for ascii-compatible messages. As a result of this,
|
||||
warnings with unicode messages are converted first to an ascii representation
|
||||
for safety. (`#2809 <https://github.com/pytest-dev/pytest/issues/2809>`_)
|
||||
|
||||
- Change return value of pytest command when ``--maxfail`` is reached from
|
||||
``2`` (interrupted) to ``1`` (failed). (`#2845
|
||||
<https://github.com/pytest-dev/pytest/issues/2845>`_)
|
||||
|
||||
- Fix issue in assertion rewriting which could lead it to rewrite modules which
|
||||
should not be rewritten. (`#2939
|
||||
<https://github.com/pytest-dev/pytest/issues/2939>`_)
|
||||
|
||||
- Handle marks without description in ``pytest.ini``. (`#2942
|
||||
<https://github.com/pytest-dev/pytest/issues/2942>`_)
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- pytest now depends on `attrs <https://pypi.org/project/attrs/>`_ for internal
|
||||
structures to ease code maintainability. (`#2641
|
||||
<https://github.com/pytest-dev/pytest/issues/2641>`_)
|
||||
|
||||
- Refactored internal Python 2/3 compatibility code to use ``six``. (`#2642
|
||||
<https://github.com/pytest-dev/pytest/issues/2642>`_)
|
||||
|
||||
- Stop vendoring ``pluggy`` - we're missing out on its latest changes for not
|
||||
much benefit (`#2719 <https://github.com/pytest-dev/pytest/issues/2719>`_)
|
||||
|
||||
- Internal refactor: simplify ascii string escaping by using the
|
||||
backslashreplace error handler in newer Python 3 versions. (`#2734
|
||||
<https://github.com/pytest-dev/pytest/issues/2734>`_)
|
||||
|
||||
- Remove unnecessary mark evaluator in unittest plugin (`#2767
|
||||
<https://github.com/pytest-dev/pytest/issues/2767>`_)
|
||||
|
||||
- Calls to ``Metafunc.addcall`` now emit a deprecation warning. This function
|
||||
is scheduled to be removed in ``pytest-4.0``. (`#2876
|
||||
<https://github.com/pytest-dev/pytest/issues/2876>`_)
|
||||
|
||||
- Internal move of the parameterset extraction to a more maintainable place.
|
||||
(`#2877 <https://github.com/pytest-dev/pytest/issues/2877>`_)
|
||||
|
||||
- Internal refactoring to simplify scope node lookup. (`#2910
|
||||
<https://github.com/pytest-dev/pytest/issues/2910>`_)
|
||||
|
||||
- Configure ``pytest`` to prevent pip from installing pytest in unsupported
|
||||
Python versions. (`#2922
|
||||
<https://github.com/pytest-dev/pytest/issues/2922>`_)
|
||||
|
||||
|
||||
Pytest 3.2.5 (2017-11-15)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Remove ``py<1.5`` restriction from ``pytest`` as this can cause version
|
||||
conflicts in some installations. (`#2926
|
||||
<https://github.com/pytest-dev/pytest/issues/2926>`_)
|
||||
|
||||
|
||||
Pytest 3.2.4 (2017-11-13)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Fix the bug where running pytest with "--pyargs" will result in Items with
|
||||
empty "parent.nodeid" if run from a different root directory. (`#2775
|
||||
- Fix the bug where running with ``--pyargs`` will result in items with
|
||||
empty ``parent.nodeid`` if run from a different root directory. (`#2775
|
||||
<https://github.com/pytest-dev/pytest/issues/2775>`_)
|
||||
|
||||
- Fix issue with @pytest.parametrize if argnames was specified as kwarg.
|
||||
- Fix issue with ``@pytest.parametrize`` if argnames was specified as keyword arguments.
|
||||
(`#2819 <https://github.com/pytest-dev/pytest/issues/2819>`_)
|
||||
|
||||
- Strip whitespace from marker names when reading them from INI config. (`#2856
|
||||
<https://github.com/pytest-dev/pytest/issues/2856>`_)
|
||||
|
||||
- Show full context of doctest source in the pytest output, if the lineno of
|
||||
- Show full context of doctest source in the pytest output, if the line number of
|
||||
failed example in the docstring is < 9. (`#2882
|
||||
<https://github.com/pytest-dev/pytest/issues/2882>`_)
|
||||
|
||||
- Match fixture paths against actual path segments in order to avoid matching folders which share a prefix.
|
||||
(`#2836 <https://github.com/pytest-dev/pytest/issues/2836>`_)
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
@@ -179,7 +1012,7 @@ Deprecations and Removals
|
||||
-------------------------
|
||||
|
||||
- ``pytest.approx`` no longer supports ``>``, ``>=``, ``<`` and ``<=``
|
||||
operators to avoid surprising/inconsistent behavior. See `the docs
|
||||
operators to avoid surprising/inconsistent behavior. See `the approx docs
|
||||
<https://docs.pytest.org/en/latest/builtin.html#pytest.approx>`_ for more
|
||||
information. (`#2003 <https://github.com/pytest-dev/pytest/issues/2003>`_)
|
||||
|
||||
@@ -503,7 +1336,7 @@ Changes
|
||||
* Testcase reports with a ``url`` attribute will now properly write this to junitxml.
|
||||
Thanks `@fushi`_ for the PR (`#1874`_).
|
||||
|
||||
* Remove common items from dict comparision output when verbosity=1. Also update
|
||||
* Remove common items from dict comparison output when verbosity=1. Also update
|
||||
the truncation message to make it clearer that pytest truncates all
|
||||
assertion messages if verbosity < 2 (`#1512`_).
|
||||
Thanks `@mattduck`_ for the PR
|
||||
@@ -515,7 +1348,7 @@ Changes
|
||||
* fix `#2013`_: turn RecordedWarning into ``namedtuple``,
|
||||
to give it a comprehensible repr while preventing unwarranted modification.
|
||||
|
||||
* fix `#2208`_: ensure a iteration limit for _pytest.compat.get_real_func.
|
||||
* fix `#2208`_: ensure an iteration limit for _pytest.compat.get_real_func.
|
||||
Thanks `@RonnyPfannschmidt`_ for the report and PR.
|
||||
|
||||
* Hooks are now verified after collection is complete, rather than right after loading installed plugins. This
|
||||
@@ -619,7 +1452,7 @@ Bug Fixes
|
||||
Notably, importing the ``anydbm`` module is fixed. (`#2248`_).
|
||||
Thanks `@pfhayes`_ for the PR.
|
||||
|
||||
* junitxml: Fix problematic case where system-out tag occured twice per testcase
|
||||
* junitxml: Fix problematic case where system-out tag occurred twice per testcase
|
||||
element in the XML report. Thanks `@kkoukiou`_ for the PR.
|
||||
|
||||
* Fix regression, pytest now skips unittest correctly if run with ``--pdb``
|
||||
@@ -2066,7 +2899,7 @@ time or change existing behaviors in order to make them less surprising/more use
|
||||
- fix issue655: work around different ways that cause python2/3
|
||||
to leak sys.exc_info into fixtures/tests causing failures in 3rd party code
|
||||
|
||||
- fix issue615: assertion re-writing did not correctly escape % signs
|
||||
- fix issue615: assertion rewriting did not correctly escape % signs
|
||||
when formatting boolean operations, which tripped over mixing
|
||||
booleans with modulo operators. Thanks to Tom Viner for the report,
|
||||
triaging and fix.
|
||||
@@ -2215,7 +3048,7 @@ time or change existing behaviors in order to make them less surprising/more use
|
||||
"::" node id specifications (copy pasted from "-v" output)
|
||||
|
||||
- fix issue544 by only removing "@NUM" at the end of "::" separated parts
|
||||
and if the part has an ".py" extension
|
||||
and if the part has a ".py" extension
|
||||
|
||||
- don't use py.std import helper, rather import things directly.
|
||||
Thanks Bruno Oliveira.
|
||||
@@ -2486,7 +3319,7 @@ time or change existing behaviors in order to make them less surprising/more use
|
||||
|
||||
would not work correctly because pytest assumes @pytest.mark.some
|
||||
gets a function to be decorated already. We now at least detect if this
|
||||
arg is an lambda and thus the example will work. Thanks Alex Gaynor
|
||||
arg is a lambda and thus the example will work. Thanks Alex Gaynor
|
||||
for bringing it up.
|
||||
|
||||
- xfail a test on pypy that checks wrong encoding/ascii (pypy does
|
||||
@@ -2799,7 +3632,7 @@ Bug fixes:
|
||||
rather use the post-2.0 parametrize features instead of yield, see:
|
||||
http://pytest.org/latest/example/parametrize.html
|
||||
- fix autouse-issue where autouse-fixtures would not be discovered
|
||||
if defined in a a/conftest.py file and tests in a/tests/test_some.py
|
||||
if defined in an a/conftest.py file and tests in a/tests/test_some.py
|
||||
- fix issue226 - LIFO ordering for fixture teardowns
|
||||
- fix issue224 - invocations with >256 char arguments now work
|
||||
- fix issue91 - add/discuss package/directory level setups in example
|
||||
@@ -3369,7 +4202,7 @@ Bug fixes:
|
||||
- make path.bestrelpath(path) return ".", note that when calling
|
||||
X.bestrelpath the assumption is that X is a directory.
|
||||
- make initial conftest discovery ignore "--" prefixed arguments
|
||||
- fix resultlog plugin when used in an multicpu/multihost xdist situation
|
||||
- fix resultlog plugin when used in a multicpu/multihost xdist situation
|
||||
(thanks Jakub Gustak)
|
||||
- perform distributed testing related reporting in the xdist-plugin
|
||||
rather than having dist-related code in the generic py.test
|
||||
|
||||
@@ -48,8 +48,7 @@ fix the bug itself.
|
||||
Fix bugs
|
||||
--------
|
||||
|
||||
Look through the GitHub issues for bugs. Here is a filter you can use:
|
||||
https://github.com/pytest-dev/pytest/labels/bug
|
||||
Look through the `GitHub issues for bugs <https://github.com/pytest-dev/pytest/labels/type:%20bug>`_.
|
||||
|
||||
:ref:`Talk <contact>` to developers to find out how you can fix specific bugs.
|
||||
|
||||
@@ -60,8 +59,7 @@ Don't forget to check the issue trackers of your favourite plugins, too!
|
||||
Implement features
|
||||
------------------
|
||||
|
||||
Look through the GitHub issues for enhancements. Here is a filter you can use:
|
||||
https://github.com/pytest-dev/pytest/labels/enhancement
|
||||
Look through the `GitHub issues for enhancements <https://github.com/pytest-dev/pytest/labels/type:%20enhancement>`_.
|
||||
|
||||
:ref:`Talk <contact>` to developers to find out how you can implement specific
|
||||
features.
|
||||
@@ -141,7 +139,7 @@ Here's a rundown of how a repository transfer usually proceeds
|
||||
* ``joedoe`` transfers repository ownership to ``pytest-dev`` administrator ``calvin``.
|
||||
* ``calvin`` creates ``pytest-xyz-admin`` and ``pytest-xyz-developers`` teams, inviting ``joedoe`` to both as **maintainer**.
|
||||
* ``calvin`` transfers repository to ``pytest-dev`` and configures team access:
|
||||
|
||||
|
||||
- ``pytest-xyz-admin`` **admin** access;
|
||||
- ``pytest-xyz-developers`` **write** access;
|
||||
|
||||
@@ -165,6 +163,7 @@ Short version
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
#. Fork the repository;
|
||||
#. enable and install pre-commit https://pre-commit.com/ to ensure styleguides and codechecks are followed
|
||||
#. Target ``master`` for bugfixes and doc changes;
|
||||
#. Target ``features`` for new features or functionality changes.
|
||||
#. Follow **PEP-8**. There's a ``tox`` command to help fixing it: ``tox -e fix-lint``.
|
||||
@@ -204,20 +203,30 @@ Here is a simple overview, with pytest-specific bits:
|
||||
$ git clone git@github.com:YOUR_GITHUB_USERNAME/pytest.git
|
||||
$ cd pytest
|
||||
# now, to fix a bug create your own branch off "master":
|
||||
|
||||
|
||||
$ git checkout -b your-bugfix-branch-name master
|
||||
|
||||
# or to instead add a feature create your own branch off "features":
|
||||
|
||||
|
||||
$ git checkout -b your-feature-branch-name features
|
||||
|
||||
Given we have "major.minor.micro" version numbers, bugfixes will usually
|
||||
be released in micro releases whereas features will be released in
|
||||
Given we have "major.minor.micro" version numbers, bugfixes will usually
|
||||
be released in micro releases whereas features will be released in
|
||||
minor releases and incompatible changes in major releases.
|
||||
|
||||
If you need some help with Git, follow this quick start
|
||||
guide: https://git.wiki.kernel.org/index.php/QuickStart
|
||||
|
||||
#. install pre-commit and install its hook on the pytest repo
|
||||
|
||||
https://pre-commit.com/ is a framework for managing and maintaining multi-language pre-commit hooks
|
||||
pytest uses pre-commit to ensure code-style and code formatting is the same
|
||||
|
||||
$ pip install --user pre-commit
|
||||
$ pre-commit install
|
||||
|
||||
Afterwards pre-commit will run whenever you commit.
|
||||
|
||||
#. Install tox
|
||||
|
||||
Tox is used to run all the tests and will automatically setup virtualenvs
|
||||
@@ -276,3 +285,15 @@ Here is a simple overview, with pytest-specific bits:
|
||||
base: features # if it's a feature
|
||||
|
||||
|
||||
Joining the Development Team
|
||||
----------------------------
|
||||
|
||||
Anyone who has successfully seen through a pull request which did not
|
||||
require any extra work from the development team to merge will
|
||||
themselves gain commit access if they so wish (if we forget to ask please send a friendly
|
||||
reminder). This does not mean your workflow to contribute changes,
|
||||
everyone goes through the same pull-request-and-review process and
|
||||
no-one merges their own pull requests unless already approved. It does however mean you can
|
||||
participate in the development process more fully since you can merge
|
||||
pull requests from other contributors yourself after having reviewed
|
||||
them.
|
||||
|
||||
@@ -12,7 +12,7 @@ taking a lot of time to make a new one.
|
||||
|
||||
#. Install development dependencies in a virtual environment with::
|
||||
|
||||
pip3 install -r tasks/requirements.txt
|
||||
pip3 install -U -r tasks/requirements.txt
|
||||
|
||||
#. Create a branch ``release-X.Y.Z`` with the version for the release.
|
||||
|
||||
@@ -22,44 +22,28 @@ taking a lot of time to make a new one.
|
||||
|
||||
Ensure your are in a clean work tree.
|
||||
|
||||
#. Generate docs, changelog, announcements and upload a package to
|
||||
your ``devpi`` staging server::
|
||||
#. Generate docs, changelog, announcements and a **local** tag::
|
||||
|
||||
invoke generate.pre-release <VERSION> <DEVPI USER> --password <DEVPI PASSWORD>
|
||||
|
||||
If ``--password`` is not given, it is assumed the user is already logged in ``devpi``.
|
||||
If you don't have an account, please ask for one.
|
||||
invoke generate.pre-release <VERSION>
|
||||
|
||||
#. Open a PR for this branch targeting ``master``.
|
||||
|
||||
#. Test the package
|
||||
#. After all tests pass and the PR has been approved, publish to PyPI by pushing the tag::
|
||||
|
||||
* **Manual method**
|
||||
git push git@github.com:pytest-dev/pytest.git <VERSION>
|
||||
|
||||
Run from multiple machines::
|
||||
Wait for the deploy to complete, then make sure it is `available on PyPI <https://pypi.org/project/pytest>`_.
|
||||
|
||||
devpi use https://devpi.net/USER/dev
|
||||
devpi test pytest==VERSION
|
||||
#. Send an email announcement with the contents from::
|
||||
|
||||
Check that tests pass for relevant combinations with::
|
||||
doc/en/announce/release-<VERSION>.rst
|
||||
|
||||
devpi list pytest
|
||||
To the following mailing lists:
|
||||
|
||||
* **CI servers**
|
||||
* pytest-dev@python.org (all releases)
|
||||
* python-announce-list@python.org (all releases)
|
||||
* testing-in-python@lists.idyll.org (only major/minor releases)
|
||||
|
||||
Configure a repository as per-instructions on
|
||||
devpi-cloud-test_ to test the package on Travis_ and AppVeyor_.
|
||||
All test environments should pass.
|
||||
|
||||
#. Publish to PyPI::
|
||||
|
||||
invoke generate.publish-release <VERSION> <DEVPI USER> <PYPI_NAME>
|
||||
|
||||
where PYPI_NAME is the name of pypi.python.org as configured in your ``~/.pypirc``
|
||||
file `for devpi <http://doc.devpi.net/latest/quickstart-releaseprocess.html?highlight=pypirc#devpi-push-releasing-to-an-external-index>`_.
|
||||
And announce it on `Twitter <https://twitter.com/>`_ with the ``#pytest`` hashtag.
|
||||
|
||||
#. After a minor/major release, merge ``release-X.Y.Z`` into ``master`` and push (or open a PR).
|
||||
|
||||
.. _devpi-cloud-test: https://github.com/obestwalter/devpi-cloud-test
|
||||
.. _AppVeyor: https://www.appveyor.com/
|
||||
.. _Travis: https://travis-ci.org
|
||||
|
||||
15
README.rst
15
README.rst
@@ -6,13 +6,13 @@
|
||||
------
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/pytest.svg
|
||||
:target: https://pypi.python.org/pypi/pytest
|
||||
:target: https://pypi.org/project/pytest/
|
||||
|
||||
.. image:: https://anaconda.org/conda-forge/pytest/badges/version.svg
|
||||
.. image:: https://img.shields.io/conda/vn/conda-forge/pytest.svg
|
||||
:target: https://anaconda.org/conda-forge/pytest
|
||||
|
||||
.. image:: https://img.shields.io/pypi/pyversions/pytest.svg
|
||||
:target: https://pypi.python.org/pypi/pytest
|
||||
:target: https://pypi.org/project/pytest/
|
||||
|
||||
.. image:: https://img.shields.io/coveralls/pytest-dev/pytest/master.svg
|
||||
:target: https://coveralls.io/r/pytest-dev/pytest
|
||||
@@ -23,6 +23,12 @@
|
||||
.. image:: https://ci.appveyor.com/api/projects/status/mrgbjaua7t33pg6b?svg=true
|
||||
:target: https://ci.appveyor.com/project/pytestbot/pytest
|
||||
|
||||
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/ambv/black
|
||||
|
||||
.. image:: https://www.codetriage.com/pytest-dev/pytest/badges/users.svg
|
||||
:target: https://www.codetriage.com/pytest-dev/pytest
|
||||
|
||||
The ``pytest`` framework makes it easy to write small tests, yet
|
||||
scales to support complex functional testing for applications and libraries.
|
||||
|
||||
@@ -34,6 +40,7 @@ An example of a simple test:
|
||||
def inc(x):
|
||||
return x + 1
|
||||
|
||||
|
||||
def test_answer():
|
||||
assert inc(3) == 5
|
||||
|
||||
@@ -76,7 +83,7 @@ Features
|
||||
- Can run `unittest <http://docs.pytest.org/en/latest/unittest.html>`_ (or trial),
|
||||
`nose <http://docs.pytest.org/en/latest/nose.html>`_ test suites out of the box;
|
||||
|
||||
- Python2.6+, Python3.3+, PyPy-2.3, Jython-2.5 (untested);
|
||||
- Python 2.7, Python 3.4+, PyPy 2.3, Jython 2.5 (untested);
|
||||
|
||||
- Rich plugin architecture, with over 315+ `external plugins <http://plugincompat.herokuapp.com>`_ and thriving community;
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
"""
|
||||
imports symbols from vendored "pluggy" if available, otherwise
|
||||
falls back to importing "pluggy" from the default namespace.
|
||||
"""
|
||||
from __future__ import absolute_import, division, print_function
|
||||
try:
|
||||
from _pytest.vendored_packages.pluggy import * # noqa
|
||||
from _pytest.vendored_packages.pluggy import __version__ # noqa
|
||||
except ImportError:
|
||||
from pluggy import * # noqa
|
||||
from pluggy import __version__ # noqa
|
||||
@@ -1,42 +0,0 @@
|
||||
"""
|
||||
This module contains deprecation messages and bits of code used elsewhere in the codebase
|
||||
that is planned to be removed in the next pytest release.
|
||||
|
||||
Keeping it in a central location makes it easy to track what is deprecated and should
|
||||
be removed when the time comes.
|
||||
"""
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
class RemovedInPytest4Warning(DeprecationWarning):
|
||||
"""warning class for features removed in pytest 4.0"""
|
||||
|
||||
|
||||
MAIN_STR_ARGS = 'passing a string to pytest.main() is deprecated, ' \
|
||||
'pass a list of arguments instead.'
|
||||
|
||||
YIELD_TESTS = 'yield tests are deprecated, and scheduled to be removed in pytest 4.0'
|
||||
|
||||
FUNCARG_PREFIX = (
|
||||
'{name}: declaring fixtures using "pytest_funcarg__" prefix is deprecated '
|
||||
'and scheduled to be removed in pytest 4.0. '
|
||||
'Please remove the prefix and use the @pytest.fixture decorator instead.')
|
||||
|
||||
SETUP_CFG_PYTEST = '[pytest] section in setup.cfg files is deprecated, use [tool:pytest] instead.'
|
||||
|
||||
GETFUNCARGVALUE = "use of getfuncargvalue is deprecated, use getfixturevalue"
|
||||
|
||||
RESULT_LOG = (
|
||||
'--result-log is deprecated and scheduled for removal in pytest 4.0.\n'
|
||||
'See https://docs.pytest.org/en/latest/usage.html#creating-resultlog-format-files for more information.'
|
||||
)
|
||||
|
||||
MARK_INFO_ATTRIBUTE = RemovedInPytest4Warning(
|
||||
"MarkInfo objects are deprecated as they contain the merged marks"
|
||||
)
|
||||
|
||||
MARK_PARAMETERSET_UNPACKING = RemovedInPytest4Warning(
|
||||
"Applying marks directly to parameters is deprecated,"
|
||||
" please use pytest.param(..., marks=...) instead.\n"
|
||||
"For more details, see: https://docs.pytest.org/en/latest/parametrize.html"
|
||||
)
|
||||
@@ -1,362 +0,0 @@
|
||||
""" discover and run doctests in modules and test files."""
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import traceback
|
||||
|
||||
import pytest
|
||||
from _pytest._code.code import ExceptionInfo, ReprFileLocation, TerminalRepr
|
||||
from _pytest.fixtures import FixtureRequest
|
||||
|
||||
|
||||
DOCTEST_REPORT_CHOICE_NONE = 'none'
|
||||
DOCTEST_REPORT_CHOICE_CDIFF = 'cdiff'
|
||||
DOCTEST_REPORT_CHOICE_NDIFF = 'ndiff'
|
||||
DOCTEST_REPORT_CHOICE_UDIFF = 'udiff'
|
||||
DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE = 'only_first_failure'
|
||||
|
||||
DOCTEST_REPORT_CHOICES = (
|
||||
DOCTEST_REPORT_CHOICE_NONE,
|
||||
DOCTEST_REPORT_CHOICE_CDIFF,
|
||||
DOCTEST_REPORT_CHOICE_NDIFF,
|
||||
DOCTEST_REPORT_CHOICE_UDIFF,
|
||||
DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE,
|
||||
)
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addini('doctest_optionflags', 'option flags for doctests',
|
||||
type="args", default=["ELLIPSIS"])
|
||||
parser.addini("doctest_encoding", 'encoding used for doctest files', default="utf-8")
|
||||
group = parser.getgroup("collect")
|
||||
group.addoption("--doctest-modules",
|
||||
action="store_true", default=False,
|
||||
help="run doctests in all .py modules",
|
||||
dest="doctestmodules")
|
||||
group.addoption("--doctest-report",
|
||||
type=str.lower, default="udiff",
|
||||
help="choose another output format for diffs on doctest failure",
|
||||
choices=DOCTEST_REPORT_CHOICES,
|
||||
dest="doctestreport")
|
||||
group.addoption("--doctest-glob",
|
||||
action="append", default=[], metavar="pat",
|
||||
help="doctests file matching pattern, default: test*.txt",
|
||||
dest="doctestglob")
|
||||
group.addoption("--doctest-ignore-import-errors",
|
||||
action="store_true", default=False,
|
||||
help="ignore doctest ImportErrors",
|
||||
dest="doctest_ignore_import_errors")
|
||||
|
||||
|
||||
def pytest_collect_file(path, parent):
|
||||
config = parent.config
|
||||
if path.ext == ".py":
|
||||
if config.option.doctestmodules:
|
||||
return DoctestModule(path, parent)
|
||||
elif _is_doctest(config, path, parent):
|
||||
return DoctestTextfile(path, parent)
|
||||
|
||||
|
||||
def _is_doctest(config, path, parent):
|
||||
if path.ext in ('.txt', '.rst') and parent.session.isinitpath(path):
|
||||
return True
|
||||
globs = config.getoption("doctestglob") or ['test*.txt']
|
||||
for glob in globs:
|
||||
if path.check(fnmatch=glob):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class ReprFailDoctest(TerminalRepr):
|
||||
|
||||
def __init__(self, reprlocation, lines):
|
||||
self.reprlocation = reprlocation
|
||||
self.lines = lines
|
||||
|
||||
def toterminal(self, tw):
|
||||
for line in self.lines:
|
||||
tw.line(line)
|
||||
self.reprlocation.toterminal(tw)
|
||||
|
||||
|
||||
class DoctestItem(pytest.Item):
|
||||
def __init__(self, name, parent, runner=None, dtest=None):
|
||||
super(DoctestItem, self).__init__(name, parent)
|
||||
self.runner = runner
|
||||
self.dtest = dtest
|
||||
self.obj = None
|
||||
self.fixture_request = None
|
||||
|
||||
def setup(self):
|
||||
if self.dtest is not None:
|
||||
self.fixture_request = _setup_fixtures(self)
|
||||
globs = dict(getfixture=self.fixture_request.getfixturevalue)
|
||||
for name, value in self.fixture_request.getfixturevalue('doctest_namespace').items():
|
||||
globs[name] = value
|
||||
self.dtest.globs.update(globs)
|
||||
|
||||
def runtest(self):
|
||||
_check_all_skipped(self.dtest)
|
||||
self.runner.run(self.dtest)
|
||||
|
||||
def repr_failure(self, excinfo):
|
||||
import doctest
|
||||
if excinfo.errisinstance((doctest.DocTestFailure,
|
||||
doctest.UnexpectedException)):
|
||||
doctestfailure = excinfo.value
|
||||
example = doctestfailure.example
|
||||
test = doctestfailure.test
|
||||
filename = test.filename
|
||||
if test.lineno is None:
|
||||
lineno = None
|
||||
else:
|
||||
lineno = test.lineno + example.lineno + 1
|
||||
message = excinfo.type.__name__
|
||||
reprlocation = ReprFileLocation(filename, lineno, message)
|
||||
checker = _get_checker()
|
||||
report_choice = _get_report_choice(self.config.getoption("doctestreport"))
|
||||
if lineno is not None:
|
||||
lines = doctestfailure.test.docstring.splitlines(False)
|
||||
# add line numbers to the left of the error message
|
||||
lines = ["%03d %s" % (i + test.lineno + 1, x)
|
||||
for (i, x) in enumerate(lines)]
|
||||
# trim docstring error lines to 10
|
||||
lines = lines[max(example.lineno - 9, 0):example.lineno + 1]
|
||||
else:
|
||||
lines = ['EXAMPLE LOCATION UNKNOWN, not showing all tests of that example']
|
||||
indent = '>>>'
|
||||
for line in example.source.splitlines():
|
||||
lines.append('??? %s %s' % (indent, line))
|
||||
indent = '...'
|
||||
if excinfo.errisinstance(doctest.DocTestFailure):
|
||||
lines += checker.output_difference(example,
|
||||
doctestfailure.got, report_choice).split("\n")
|
||||
else:
|
||||
inner_excinfo = ExceptionInfo(excinfo.value.exc_info)
|
||||
lines += ["UNEXPECTED EXCEPTION: %s" %
|
||||
repr(inner_excinfo.value)]
|
||||
lines += traceback.format_exception(*excinfo.value.exc_info)
|
||||
return ReprFailDoctest(reprlocation, lines)
|
||||
else:
|
||||
return super(DoctestItem, self).repr_failure(excinfo)
|
||||
|
||||
def reportinfo(self):
|
||||
return self.fspath, self.dtest.lineno, "[doctest] %s" % self.name
|
||||
|
||||
|
||||
def _get_flag_lookup():
|
||||
import doctest
|
||||
return dict(DONT_ACCEPT_TRUE_FOR_1=doctest.DONT_ACCEPT_TRUE_FOR_1,
|
||||
DONT_ACCEPT_BLANKLINE=doctest.DONT_ACCEPT_BLANKLINE,
|
||||
NORMALIZE_WHITESPACE=doctest.NORMALIZE_WHITESPACE,
|
||||
ELLIPSIS=doctest.ELLIPSIS,
|
||||
IGNORE_EXCEPTION_DETAIL=doctest.IGNORE_EXCEPTION_DETAIL,
|
||||
COMPARISON_FLAGS=doctest.COMPARISON_FLAGS,
|
||||
ALLOW_UNICODE=_get_allow_unicode_flag(),
|
||||
ALLOW_BYTES=_get_allow_bytes_flag(),
|
||||
)
|
||||
|
||||
|
||||
def get_optionflags(parent):
|
||||
optionflags_str = parent.config.getini("doctest_optionflags")
|
||||
flag_lookup_table = _get_flag_lookup()
|
||||
flag_acc = 0
|
||||
for flag in optionflags_str:
|
||||
flag_acc |= flag_lookup_table[flag]
|
||||
return flag_acc
|
||||
|
||||
|
||||
class DoctestTextfile(pytest.Module):
|
||||
obj = None
|
||||
|
||||
def collect(self):
|
||||
import doctest
|
||||
|
||||
# inspired by doctest.testfile; ideally we would use it directly,
|
||||
# but it doesn't support passing a custom checker
|
||||
encoding = self.config.getini("doctest_encoding")
|
||||
text = self.fspath.read_text(encoding)
|
||||
filename = str(self.fspath)
|
||||
name = self.fspath.basename
|
||||
globs = {'__name__': '__main__'}
|
||||
|
||||
optionflags = get_optionflags(self)
|
||||
runner = doctest.DebugRunner(verbose=0, optionflags=optionflags,
|
||||
checker=_get_checker())
|
||||
_fix_spoof_python2(runner, encoding)
|
||||
|
||||
parser = doctest.DocTestParser()
|
||||
test = parser.get_doctest(text, globs, name, filename, 0)
|
||||
if test.examples:
|
||||
yield DoctestItem(test.name, self, runner, test)
|
||||
|
||||
|
||||
def _check_all_skipped(test):
|
||||
"""raises pytest.skip() if all examples in the given DocTest have the SKIP
|
||||
option set.
|
||||
"""
|
||||
import doctest
|
||||
all_skipped = all(x.options.get(doctest.SKIP, False) for x in test.examples)
|
||||
if all_skipped:
|
||||
pytest.skip('all tests skipped by +SKIP option')
|
||||
|
||||
|
||||
class DoctestModule(pytest.Module):
|
||||
def collect(self):
|
||||
import doctest
|
||||
if self.fspath.basename == "conftest.py":
|
||||
module = self.config.pluginmanager._importconftest(self.fspath)
|
||||
else:
|
||||
try:
|
||||
module = self.fspath.pyimport()
|
||||
except ImportError:
|
||||
if self.config.getvalue('doctest_ignore_import_errors'):
|
||||
pytest.skip('unable to import module %r' % self.fspath)
|
||||
else:
|
||||
raise
|
||||
# uses internal doctest module parsing mechanism
|
||||
finder = doctest.DocTestFinder()
|
||||
optionflags = get_optionflags(self)
|
||||
runner = doctest.DebugRunner(verbose=0, optionflags=optionflags,
|
||||
checker=_get_checker())
|
||||
|
||||
for test in finder.find(module, module.__name__):
|
||||
if test.examples: # skip empty doctests
|
||||
yield DoctestItem(test.name, self, runner, test)
|
||||
|
||||
|
||||
def _setup_fixtures(doctest_item):
|
||||
"""
|
||||
Used by DoctestTextfile and DoctestItem to setup fixture information.
|
||||
"""
|
||||
def func():
|
||||
pass
|
||||
|
||||
doctest_item.funcargs = {}
|
||||
fm = doctest_item.session._fixturemanager
|
||||
doctest_item._fixtureinfo = fm.getfixtureinfo(node=doctest_item, func=func,
|
||||
cls=None, funcargs=False)
|
||||
fixture_request = FixtureRequest(doctest_item)
|
||||
fixture_request._fillfixtures()
|
||||
return fixture_request
|
||||
|
||||
|
||||
def _get_checker():
|
||||
"""
|
||||
Returns a doctest.OutputChecker subclass that takes in account the
|
||||
ALLOW_UNICODE option to ignore u'' prefixes in strings and ALLOW_BYTES
|
||||
to strip b'' prefixes.
|
||||
Useful when the same doctest should run in Python 2 and Python 3.
|
||||
|
||||
An inner class is used to avoid importing "doctest" at the module
|
||||
level.
|
||||
"""
|
||||
if hasattr(_get_checker, 'LiteralsOutputChecker'):
|
||||
return _get_checker.LiteralsOutputChecker()
|
||||
|
||||
import doctest
|
||||
import re
|
||||
|
||||
class LiteralsOutputChecker(doctest.OutputChecker):
|
||||
"""
|
||||
Copied from doctest_nose_plugin.py from the nltk project:
|
||||
https://github.com/nltk/nltk
|
||||
|
||||
Further extended to also support byte literals.
|
||||
"""
|
||||
|
||||
_unicode_literal_re = re.compile(r"(\W|^)[uU]([rR]?[\'\"])", re.UNICODE)
|
||||
_bytes_literal_re = re.compile(r"(\W|^)[bB]([rR]?[\'\"])", re.UNICODE)
|
||||
|
||||
def check_output(self, want, got, optionflags):
|
||||
res = doctest.OutputChecker.check_output(self, want, got,
|
||||
optionflags)
|
||||
if res:
|
||||
return True
|
||||
|
||||
allow_unicode = optionflags & _get_allow_unicode_flag()
|
||||
allow_bytes = optionflags & _get_allow_bytes_flag()
|
||||
if not allow_unicode and not allow_bytes:
|
||||
return False
|
||||
|
||||
else: # pragma: no cover
|
||||
def remove_prefixes(regex, txt):
|
||||
return re.sub(regex, r'\1\2', txt)
|
||||
|
||||
if allow_unicode:
|
||||
want = remove_prefixes(self._unicode_literal_re, want)
|
||||
got = remove_prefixes(self._unicode_literal_re, got)
|
||||
if allow_bytes:
|
||||
want = remove_prefixes(self._bytes_literal_re, want)
|
||||
got = remove_prefixes(self._bytes_literal_re, got)
|
||||
res = doctest.OutputChecker.check_output(self, want, got,
|
||||
optionflags)
|
||||
return res
|
||||
|
||||
_get_checker.LiteralsOutputChecker = LiteralsOutputChecker
|
||||
return _get_checker.LiteralsOutputChecker()
|
||||
|
||||
|
||||
def _get_allow_unicode_flag():
|
||||
"""
|
||||
Registers and returns the ALLOW_UNICODE flag.
|
||||
"""
|
||||
import doctest
|
||||
return doctest.register_optionflag('ALLOW_UNICODE')
|
||||
|
||||
|
||||
def _get_allow_bytes_flag():
|
||||
"""
|
||||
Registers and returns the ALLOW_BYTES flag.
|
||||
"""
|
||||
import doctest
|
||||
return doctest.register_optionflag('ALLOW_BYTES')
|
||||
|
||||
|
||||
def _get_report_choice(key):
|
||||
"""
|
||||
This function returns the actual `doctest` module flag value, we want to do it as late as possible to avoid
|
||||
importing `doctest` and all its dependencies when parsing options, as it adds overhead and breaks tests.
|
||||
"""
|
||||
import doctest
|
||||
|
||||
return {
|
||||
DOCTEST_REPORT_CHOICE_UDIFF: doctest.REPORT_UDIFF,
|
||||
DOCTEST_REPORT_CHOICE_CDIFF: doctest.REPORT_CDIFF,
|
||||
DOCTEST_REPORT_CHOICE_NDIFF: doctest.REPORT_NDIFF,
|
||||
DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE: doctest.REPORT_ONLY_FIRST_FAILURE,
|
||||
DOCTEST_REPORT_CHOICE_NONE: 0,
|
||||
}[key]
|
||||
|
||||
|
||||
def _fix_spoof_python2(runner, encoding):
|
||||
"""
|
||||
Installs a "SpoofOut" into the given DebugRunner so it properly deals with unicode output. This
|
||||
should patch only doctests for text files because they don't have a way to declare their
|
||||
encoding. Doctests in docstrings from Python modules don't have the same problem given that
|
||||
Python already decoded the strings.
|
||||
|
||||
This fixes the problem related in issue #2434.
|
||||
"""
|
||||
from _pytest.compat import _PY2
|
||||
if not _PY2:
|
||||
return
|
||||
|
||||
from doctest import _SpoofOut
|
||||
|
||||
class UnicodeSpoof(_SpoofOut):
|
||||
|
||||
def getvalue(self):
|
||||
result = _SpoofOut.getvalue(self)
|
||||
if encoding:
|
||||
result = result.decode(encoding)
|
||||
return result
|
||||
|
||||
runner._fakeout = UnicodeSpoof()
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def doctest_namespace():
|
||||
"""
|
||||
Inject names into the doctest namespace.
|
||||
"""
|
||||
return dict()
|
||||
835
_pytest/main.py
835
_pytest/main.py
@@ -1,835 +0,0 @@
|
||||
""" core implementation of testing process: init, session, runtest loop. """
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import functools
|
||||
import os
|
||||
import sys
|
||||
|
||||
import _pytest
|
||||
from _pytest import nodes
|
||||
import _pytest._code
|
||||
import py
|
||||
try:
|
||||
from collections import MutableMapping as MappingMixin
|
||||
except ImportError:
|
||||
from UserDict import DictMixin as MappingMixin
|
||||
|
||||
from _pytest.config import directory_arg, UsageError, hookimpl
|
||||
from _pytest.outcomes import exit
|
||||
from _pytest.runner import collect_one_node
|
||||
|
||||
tracebackcutdir = py.path.local(_pytest.__file__).dirpath()
|
||||
|
||||
# exitcodes for the command line
|
||||
EXIT_OK = 0
|
||||
EXIT_TESTSFAILED = 1
|
||||
EXIT_INTERRUPTED = 2
|
||||
EXIT_INTERNALERROR = 3
|
||||
EXIT_USAGEERROR = 4
|
||||
EXIT_NOTESTSCOLLECTED = 5
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addini("norecursedirs", "directory patterns to avoid for recursion",
|
||||
type="args", default=['.*', 'build', 'dist', 'CVS', '_darcs', '{arch}', '*.egg', 'venv'])
|
||||
parser.addini("testpaths", "directories to search for tests when no files or directories are given in the "
|
||||
"command line.",
|
||||
type="args", default=[])
|
||||
# parser.addini("dirpatterns",
|
||||
# "patterns specifying possible locations of test files",
|
||||
# type="linelist", default=["**/test_*.txt",
|
||||
# "**/test_*.py", "**/*_test.py"]
|
||||
# )
|
||||
group = parser.getgroup("general", "running and selection options")
|
||||
group._addoption('-x', '--exitfirst', action="store_const",
|
||||
dest="maxfail", const=1,
|
||||
help="exit instantly on first error or failed test."),
|
||||
group._addoption('--maxfail', metavar="num",
|
||||
action="store", type=int, dest="maxfail", default=0,
|
||||
help="exit after first num failures or errors.")
|
||||
group._addoption('--strict', action="store_true",
|
||||
help="marks not registered in configuration file raise errors.")
|
||||
group._addoption("-c", metavar="file", type=str, dest="inifilename",
|
||||
help="load configuration from `file` instead of trying to locate one of the implicit "
|
||||
"configuration files.")
|
||||
group._addoption("--continue-on-collection-errors", action="store_true",
|
||||
default=False, dest="continue_on_collection_errors",
|
||||
help="Force test execution even if collection errors occur.")
|
||||
|
||||
group = parser.getgroup("collect", "collection")
|
||||
group.addoption('--collectonly', '--collect-only', action="store_true",
|
||||
help="only collect tests, don't execute them."),
|
||||
group.addoption('--pyargs', action="store_true",
|
||||
help="try to interpret all arguments as python packages.")
|
||||
group.addoption("--ignore", action="append", metavar="path",
|
||||
help="ignore path during collection (multi-allowed).")
|
||||
# when changing this to --conf-cut-dir, config.py Conftest.setinitial
|
||||
# needs upgrading as well
|
||||
group.addoption('--confcutdir', dest="confcutdir", default=None,
|
||||
metavar="dir", type=functools.partial(directory_arg, optname="--confcutdir"),
|
||||
help="only load conftest.py's relative to specified dir.")
|
||||
group.addoption('--noconftest', action="store_true",
|
||||
dest="noconftest", default=False,
|
||||
help="Don't load any conftest.py files.")
|
||||
group.addoption('--keepduplicates', '--keep-duplicates', action="store_true",
|
||||
dest="keepduplicates", default=False,
|
||||
help="Keep duplicate tests.")
|
||||
group.addoption('--collect-in-virtualenv', action='store_true',
|
||||
dest='collect_in_virtualenv', default=False,
|
||||
help="Don't ignore tests in a local virtualenv directory")
|
||||
|
||||
group = parser.getgroup("debugconfig",
|
||||
"test session debugging and configuration")
|
||||
group.addoption('--basetemp', dest="basetemp", default=None, metavar="dir",
|
||||
help="base temporary directory for this test run.")
|
||||
|
||||
|
||||
def pytest_namespace():
|
||||
"""keeping this one works around a deeper startup issue in pytest
|
||||
|
||||
i tried to find it for a while but the amount of time turned unsustainable,
|
||||
so i put a hack in to revisit later
|
||||
"""
|
||||
return {}
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
__import__('pytest').config = config # compatibiltiy
|
||||
|
||||
|
||||
def wrap_session(config, doit):
|
||||
"""Skeleton command line program"""
|
||||
session = Session(config)
|
||||
session.exitstatus = EXIT_OK
|
||||
initstate = 0
|
||||
try:
|
||||
try:
|
||||
config._do_configure()
|
||||
initstate = 1
|
||||
config.hook.pytest_sessionstart(session=session)
|
||||
initstate = 2
|
||||
session.exitstatus = doit(config, session) or 0
|
||||
except UsageError:
|
||||
raise
|
||||
except KeyboardInterrupt:
|
||||
excinfo = _pytest._code.ExceptionInfo()
|
||||
if initstate < 2 and isinstance(excinfo.value, exit.Exception):
|
||||
sys.stderr.write('{0}: {1}\n'.format(
|
||||
excinfo.typename, excinfo.value.msg))
|
||||
config.hook.pytest_keyboard_interrupt(excinfo=excinfo)
|
||||
session.exitstatus = EXIT_INTERRUPTED
|
||||
except: # noqa
|
||||
excinfo = _pytest._code.ExceptionInfo()
|
||||
config.notify_exception(excinfo, config.option)
|
||||
session.exitstatus = EXIT_INTERNALERROR
|
||||
if excinfo.errisinstance(SystemExit):
|
||||
sys.stderr.write("mainloop: caught Spurious SystemExit!\n")
|
||||
|
||||
finally:
|
||||
excinfo = None # Explicitly break reference cycle.
|
||||
session.startdir.chdir()
|
||||
if initstate >= 2:
|
||||
config.hook.pytest_sessionfinish(
|
||||
session=session,
|
||||
exitstatus=session.exitstatus)
|
||||
config._ensure_unconfigure()
|
||||
return session.exitstatus
|
||||
|
||||
|
||||
def pytest_cmdline_main(config):
|
||||
return wrap_session(config, _main)
|
||||
|
||||
|
||||
def _main(config, session):
|
||||
""" default command line protocol for initialization, session,
|
||||
running tests and reporting. """
|
||||
config.hook.pytest_collection(session=session)
|
||||
config.hook.pytest_runtestloop(session=session)
|
||||
|
||||
if session.testsfailed:
|
||||
return EXIT_TESTSFAILED
|
||||
elif session.testscollected == 0:
|
||||
return EXIT_NOTESTSCOLLECTED
|
||||
|
||||
|
||||
def pytest_collection(session):
|
||||
return session.perform_collect()
|
||||
|
||||
|
||||
def pytest_runtestloop(session):
|
||||
if (session.testsfailed and
|
||||
not session.config.option.continue_on_collection_errors):
|
||||
raise session.Interrupted(
|
||||
"%d errors during collection" % session.testsfailed)
|
||||
|
||||
if session.config.option.collectonly:
|
||||
return True
|
||||
|
||||
for i, item in enumerate(session.items):
|
||||
nextitem = session.items[i + 1] if i + 1 < len(session.items) else None
|
||||
item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
|
||||
if session.shouldstop:
|
||||
raise session.Interrupted(session.shouldstop)
|
||||
return True
|
||||
|
||||
|
||||
def _in_venv(path):
|
||||
"""Attempts to detect if ``path`` is the root of a Virtual Environment by
|
||||
checking for the existence of the appropriate activate script"""
|
||||
bindir = path.join('Scripts' if sys.platform.startswith('win') else 'bin')
|
||||
if not bindir.exists():
|
||||
return False
|
||||
activates = ('activate', 'activate.csh', 'activate.fish',
|
||||
'Activate', 'Activate.bat', 'Activate.ps1')
|
||||
return any([fname.basename in activates for fname in bindir.listdir()])
|
||||
|
||||
|
||||
def pytest_ignore_collect(path, config):
|
||||
ignore_paths = config._getconftest_pathlist("collect_ignore", path=path.dirpath())
|
||||
ignore_paths = ignore_paths or []
|
||||
excludeopt = config.getoption("ignore")
|
||||
if excludeopt:
|
||||
ignore_paths.extend([py.path.local(x) for x in excludeopt])
|
||||
|
||||
if py.path.local(path) in ignore_paths:
|
||||
return True
|
||||
|
||||
allow_in_venv = config.getoption("collect_in_virtualenv")
|
||||
if _in_venv(path) and not allow_in_venv:
|
||||
return True
|
||||
|
||||
# Skip duplicate paths.
|
||||
keepduplicates = config.getoption("keepduplicates")
|
||||
duplicate_paths = config.pluginmanager._duplicatepaths
|
||||
if not keepduplicates:
|
||||
if path in duplicate_paths:
|
||||
return True
|
||||
else:
|
||||
duplicate_paths.add(path)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class FSHookProxy:
|
||||
def __init__(self, fspath, pm, remove_mods):
|
||||
self.fspath = fspath
|
||||
self.pm = pm
|
||||
self.remove_mods = remove_mods
|
||||
|
||||
def __getattr__(self, name):
|
||||
x = self.pm.subset_hook_caller(name, remove_plugins=self.remove_mods)
|
||||
self.__dict__[name] = x
|
||||
return x
|
||||
|
||||
|
||||
class _CompatProperty(object):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __get__(self, obj, owner):
|
||||
if obj is None:
|
||||
return self
|
||||
|
||||
# TODO: reenable in the features branch
|
||||
# warnings.warn(
|
||||
# "usage of {owner!r}.{name} is deprecated, please use pytest.{name} instead".format(
|
||||
# name=self.name, owner=type(owner).__name__),
|
||||
# PendingDeprecationWarning, stacklevel=2)
|
||||
return getattr(__import__('pytest'), self.name)
|
||||
|
||||
|
||||
class NodeKeywords(MappingMixin):
|
||||
def __init__(self, node):
|
||||
self.node = node
|
||||
self.parent = node.parent
|
||||
self._markers = {node.name: True}
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
return self._markers[key]
|
||||
except KeyError:
|
||||
if self.parent is None:
|
||||
raise
|
||||
return self.parent.keywords[key]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self._markers[key] = value
|
||||
|
||||
def __delitem__(self, key):
|
||||
raise ValueError("cannot delete key in keywords dict")
|
||||
|
||||
def __iter__(self):
|
||||
seen = set(self._markers)
|
||||
if self.parent is not None:
|
||||
seen.update(self.parent.keywords)
|
||||
return iter(seen)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.__iter__())
|
||||
|
||||
def keys(self):
|
||||
return list(self)
|
||||
|
||||
def __repr__(self):
|
||||
return "<NodeKeywords for node %s>" % (self.node, )
|
||||
|
||||
|
||||
class Node(object):
|
||||
""" base class for Collector and Item the test collection tree.
|
||||
Collector subclasses have children, Items are terminal nodes."""
|
||||
|
||||
def __init__(self, name, parent=None, config=None, session=None):
|
||||
#: a unique name within the scope of the parent node
|
||||
self.name = name
|
||||
|
||||
#: the parent collector node.
|
||||
self.parent = parent
|
||||
|
||||
#: the pytest config object
|
||||
self.config = config or parent.config
|
||||
|
||||
#: the session this node is part of
|
||||
self.session = session or parent.session
|
||||
|
||||
#: filesystem path where this node was collected from (can be None)
|
||||
self.fspath = getattr(parent, 'fspath', None)
|
||||
|
||||
#: keywords/markers collected from all scopes
|
||||
self.keywords = NodeKeywords(self)
|
||||
|
||||
#: allow adding of extra keywords to use for matching
|
||||
self.extra_keyword_matches = set()
|
||||
|
||||
# used for storing artificial fixturedefs for direct parametrization
|
||||
self._name2pseudofixturedef = {}
|
||||
|
||||
@property
|
||||
def ihook(self):
|
||||
""" fspath sensitive hook proxy used to call pytest hooks"""
|
||||
return self.session.gethookproxy(self.fspath)
|
||||
|
||||
Module = _CompatProperty("Module")
|
||||
Class = _CompatProperty("Class")
|
||||
Instance = _CompatProperty("Instance")
|
||||
Function = _CompatProperty("Function")
|
||||
File = _CompatProperty("File")
|
||||
Item = _CompatProperty("Item")
|
||||
|
||||
def _getcustomclass(self, name):
|
||||
maybe_compatprop = getattr(type(self), name)
|
||||
if isinstance(maybe_compatprop, _CompatProperty):
|
||||
return getattr(__import__('pytest'), name)
|
||||
else:
|
||||
cls = getattr(self, name)
|
||||
# TODO: reenable in the features branch
|
||||
# warnings.warn("use of node.%s is deprecated, "
|
||||
# "use pytest_pycollect_makeitem(...) to create custom "
|
||||
# "collection nodes" % name, category=DeprecationWarning)
|
||||
return cls
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s %r>" % (self.__class__.__name__,
|
||||
getattr(self, 'name', None))
|
||||
|
||||
def warn(self, code, message):
|
||||
""" generate a warning with the given code and message for this
|
||||
item. """
|
||||
assert isinstance(code, str)
|
||||
fslocation = getattr(self, "location", None)
|
||||
if fslocation is None:
|
||||
fslocation = getattr(self, "fspath", None)
|
||||
self.ihook.pytest_logwarning.call_historic(kwargs=dict(
|
||||
code=code, message=message,
|
||||
nodeid=self.nodeid, fslocation=fslocation))
|
||||
|
||||
# methods for ordering nodes
|
||||
@property
|
||||
def nodeid(self):
|
||||
""" a ::-separated string denoting its collection tree address. """
|
||||
try:
|
||||
return self._nodeid
|
||||
except AttributeError:
|
||||
self._nodeid = x = self._makeid()
|
||||
return x
|
||||
|
||||
def _makeid(self):
|
||||
return self.parent.nodeid + "::" + self.name
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.nodeid)
|
||||
|
||||
def setup(self):
|
||||
pass
|
||||
|
||||
def teardown(self):
|
||||
pass
|
||||
|
||||
def _memoizedcall(self, attrname, function):
|
||||
exattrname = "_ex_" + attrname
|
||||
failure = getattr(self, exattrname, None)
|
||||
if failure is not None:
|
||||
py.builtin._reraise(failure[0], failure[1], failure[2])
|
||||
if hasattr(self, attrname):
|
||||
return getattr(self, attrname)
|
||||
try:
|
||||
res = function()
|
||||
except py.builtin._sysex:
|
||||
raise
|
||||
except: # noqa
|
||||
failure = sys.exc_info()
|
||||
setattr(self, exattrname, failure)
|
||||
raise
|
||||
setattr(self, attrname, res)
|
||||
return res
|
||||
|
||||
def listchain(self):
|
||||
""" return list of all parent collectors up to self,
|
||||
starting from root of collection tree. """
|
||||
chain = []
|
||||
item = self
|
||||
while item is not None:
|
||||
chain.append(item)
|
||||
item = item.parent
|
||||
chain.reverse()
|
||||
return chain
|
||||
|
||||
def add_marker(self, marker):
|
||||
""" dynamically add a marker object to the node.
|
||||
|
||||
``marker`` can be a string or pytest.mark.* instance.
|
||||
"""
|
||||
from _pytest.mark import MarkDecorator, MARK_GEN
|
||||
if isinstance(marker, py.builtin._basestring):
|
||||
marker = getattr(MARK_GEN, marker)
|
||||
elif not isinstance(marker, MarkDecorator):
|
||||
raise ValueError("is not a string or pytest.mark.* Marker")
|
||||
self.keywords[marker.name] = marker
|
||||
|
||||
def get_marker(self, name):
|
||||
""" get a marker object from this node or None if
|
||||
the node doesn't have a marker with that name. """
|
||||
val = self.keywords.get(name, None)
|
||||
if val is not None:
|
||||
from _pytest.mark import MarkInfo, MarkDecorator
|
||||
if isinstance(val, (MarkDecorator, MarkInfo)):
|
||||
return val
|
||||
|
||||
def listextrakeywords(self):
|
||||
""" Return a set of all extra keywords in self and any parents."""
|
||||
extra_keywords = set()
|
||||
item = self
|
||||
for item in self.listchain():
|
||||
extra_keywords.update(item.extra_keyword_matches)
|
||||
return extra_keywords
|
||||
|
||||
def listnames(self):
|
||||
return [x.name for x in self.listchain()]
|
||||
|
||||
def addfinalizer(self, fin):
|
||||
""" register a function to be called when this node is finalized.
|
||||
|
||||
This method can only be called when this node is active
|
||||
in a setup chain, for example during self.setup().
|
||||
"""
|
||||
self.session._setupstate.addfinalizer(fin, self)
|
||||
|
||||
def getparent(self, cls):
|
||||
""" get the next parent node (including ourself)
|
||||
which is an instance of the given class"""
|
||||
current = self
|
||||
while current and not isinstance(current, cls):
|
||||
current = current.parent
|
||||
return current
|
||||
|
||||
def _prunetraceback(self, excinfo):
|
||||
pass
|
||||
|
||||
def _repr_failure_py(self, excinfo, style=None):
|
||||
fm = self.session._fixturemanager
|
||||
if excinfo.errisinstance(fm.FixtureLookupError):
|
||||
return excinfo.value.formatrepr()
|
||||
tbfilter = True
|
||||
if self.config.option.fulltrace:
|
||||
style = "long"
|
||||
else:
|
||||
tb = _pytest._code.Traceback([excinfo.traceback[-1]])
|
||||
self._prunetraceback(excinfo)
|
||||
if len(excinfo.traceback) == 0:
|
||||
excinfo.traceback = tb
|
||||
tbfilter = False # prunetraceback already does it
|
||||
if style == "auto":
|
||||
style = "long"
|
||||
# XXX should excinfo.getrepr record all data and toterminal() process it?
|
||||
if style is None:
|
||||
if self.config.option.tbstyle == "short":
|
||||
style = "short"
|
||||
else:
|
||||
style = "long"
|
||||
|
||||
try:
|
||||
os.getcwd()
|
||||
abspath = False
|
||||
except OSError:
|
||||
abspath = True
|
||||
|
||||
return excinfo.getrepr(funcargs=True, abspath=abspath,
|
||||
showlocals=self.config.option.showlocals,
|
||||
style=style, tbfilter=tbfilter)
|
||||
|
||||
repr_failure = _repr_failure_py
|
||||
|
||||
|
||||
class Collector(Node):
|
||||
""" Collector instances create children through collect()
|
||||
and thus iteratively build a tree.
|
||||
"""
|
||||
|
||||
class CollectError(Exception):
|
||||
""" an error during collection, contains a custom message. """
|
||||
|
||||
def collect(self):
|
||||
""" returns a list of children (items and collectors)
|
||||
for this collection node.
|
||||
"""
|
||||
raise NotImplementedError("abstract")
|
||||
|
||||
def repr_failure(self, excinfo):
|
||||
""" represent a collection failure. """
|
||||
if excinfo.errisinstance(self.CollectError):
|
||||
exc = excinfo.value
|
||||
return str(exc.args[0])
|
||||
return self._repr_failure_py(excinfo, style="short")
|
||||
|
||||
def _prunetraceback(self, excinfo):
|
||||
if hasattr(self, 'fspath'):
|
||||
traceback = excinfo.traceback
|
||||
ntraceback = traceback.cut(path=self.fspath)
|
||||
if ntraceback == traceback:
|
||||
ntraceback = ntraceback.cut(excludepath=tracebackcutdir)
|
||||
excinfo.traceback = ntraceback.filter()
|
||||
|
||||
|
||||
class FSCollector(Collector):
|
||||
def __init__(self, fspath, parent=None, config=None, session=None):
|
||||
fspath = py.path.local(fspath) # xxx only for test_resultlog.py?
|
||||
name = fspath.basename
|
||||
if parent is not None:
|
||||
rel = fspath.relto(parent.fspath)
|
||||
if rel:
|
||||
name = rel
|
||||
name = name.replace(os.sep, nodes.SEP)
|
||||
super(FSCollector, self).__init__(name, parent, config, session)
|
||||
self.fspath = fspath
|
||||
|
||||
def _check_initialpaths_for_relpath(self):
|
||||
for initialpath in self.session._initialpaths:
|
||||
if self.fspath.common(initialpath) == initialpath:
|
||||
return self.fspath.relto(initialpath.dirname)
|
||||
|
||||
def _makeid(self):
|
||||
relpath = self.fspath.relto(self.config.rootdir)
|
||||
|
||||
if not relpath:
|
||||
relpath = self._check_initialpaths_for_relpath()
|
||||
if os.sep != nodes.SEP:
|
||||
relpath = relpath.replace(os.sep, nodes.SEP)
|
||||
return relpath
|
||||
|
||||
|
||||
class File(FSCollector):
|
||||
""" base class for collecting tests from a file. """
|
||||
|
||||
|
||||
class Item(Node):
|
||||
""" a basic test invocation item. Note that for a single function
|
||||
there might be multiple test invocation items.
|
||||
"""
|
||||
nextitem = None
|
||||
|
||||
def __init__(self, name, parent=None, config=None, session=None):
|
||||
super(Item, self).__init__(name, parent, config, session)
|
||||
self._report_sections = []
|
||||
|
||||
def add_report_section(self, when, key, content):
|
||||
"""
|
||||
Adds a new report section, similar to what's done internally to add stdout and
|
||||
stderr captured output::
|
||||
|
||||
item.add_report_section("call", "stdout", "report section contents")
|
||||
|
||||
:param str when:
|
||||
One of the possible capture states, ``"setup"``, ``"call"``, ``"teardown"``.
|
||||
:param str key:
|
||||
Name of the section, can be customized at will. Pytest uses ``"stdout"`` and
|
||||
``"stderr"`` internally.
|
||||
|
||||
:param str content:
|
||||
The full contents as a string.
|
||||
"""
|
||||
if content:
|
||||
self._report_sections.append((when, key, content))
|
||||
|
||||
def reportinfo(self):
|
||||
return self.fspath, None, ""
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
try:
|
||||
return self._location
|
||||
except AttributeError:
|
||||
location = self.reportinfo()
|
||||
# bestrelpath is a quite slow function
|
||||
cache = self.config.__dict__.setdefault("_bestrelpathcache", {})
|
||||
try:
|
||||
fspath = cache[location[0]]
|
||||
except KeyError:
|
||||
fspath = self.session.fspath.bestrelpath(location[0])
|
||||
cache[location[0]] = fspath
|
||||
location = (fspath, location[1], str(location[2]))
|
||||
self._location = location
|
||||
return location
|
||||
|
||||
|
||||
class NoMatch(Exception):
|
||||
""" raised if matching cannot locate a matching names. """
|
||||
|
||||
|
||||
class Interrupted(KeyboardInterrupt):
|
||||
""" signals an interrupted test run. """
|
||||
__module__ = 'builtins' # for py3
|
||||
|
||||
|
||||
class Session(FSCollector):
|
||||
Interrupted = Interrupted
|
||||
|
||||
def __init__(self, config):
|
||||
FSCollector.__init__(self, config.rootdir, parent=None,
|
||||
config=config, session=self)
|
||||
self.testsfailed = 0
|
||||
self.testscollected = 0
|
||||
self.shouldstop = False
|
||||
self.trace = config.trace.root.get("collection")
|
||||
self._norecursepatterns = config.getini("norecursedirs")
|
||||
self.startdir = py.path.local()
|
||||
self.config.pluginmanager.register(self, name="session")
|
||||
|
||||
def _makeid(self):
|
||||
return ""
|
||||
|
||||
@hookimpl(tryfirst=True)
|
||||
def pytest_collectstart(self):
|
||||
if self.shouldstop:
|
||||
raise self.Interrupted(self.shouldstop)
|
||||
|
||||
@hookimpl(tryfirst=True)
|
||||
def pytest_runtest_logreport(self, report):
|
||||
if report.failed and not hasattr(report, 'wasxfail'):
|
||||
self.testsfailed += 1
|
||||
maxfail = self.config.getvalue("maxfail")
|
||||
if maxfail and self.testsfailed >= maxfail:
|
||||
self.shouldstop = "stopping after %d failures" % (
|
||||
self.testsfailed)
|
||||
pytest_collectreport = pytest_runtest_logreport
|
||||
|
||||
def isinitpath(self, path):
|
||||
return path in self._initialpaths
|
||||
|
||||
def gethookproxy(self, fspath):
|
||||
# check if we have the common case of running
|
||||
# hooks with all conftest.py filesall conftest.py
|
||||
pm = self.config.pluginmanager
|
||||
my_conftestmodules = pm._getconftestmodules(fspath)
|
||||
remove_mods = pm._conftest_plugins.difference(my_conftestmodules)
|
||||
if remove_mods:
|
||||
# one or more conftests are not in use at this fspath
|
||||
proxy = FSHookProxy(fspath, pm, remove_mods)
|
||||
else:
|
||||
# all plugis are active for this fspath
|
||||
proxy = self.config.hook
|
||||
return proxy
|
||||
|
||||
def perform_collect(self, args=None, genitems=True):
|
||||
hook = self.config.hook
|
||||
try:
|
||||
items = self._perform_collect(args, genitems)
|
||||
self.config.pluginmanager.check_pending()
|
||||
hook.pytest_collection_modifyitems(session=self,
|
||||
config=self.config, items=items)
|
||||
finally:
|
||||
hook.pytest_collection_finish(session=self)
|
||||
self.testscollected = len(items)
|
||||
return items
|
||||
|
||||
def _perform_collect(self, args, genitems):
|
||||
if args is None:
|
||||
args = self.config.args
|
||||
self.trace("perform_collect", self, args)
|
||||
self.trace.root.indent += 1
|
||||
self._notfound = []
|
||||
self._initialpaths = set()
|
||||
self._initialparts = []
|
||||
self.items = items = []
|
||||
for arg in args:
|
||||
parts = self._parsearg(arg)
|
||||
self._initialparts.append(parts)
|
||||
self._initialpaths.add(parts[0])
|
||||
rep = collect_one_node(self)
|
||||
self.ihook.pytest_collectreport(report=rep)
|
||||
self.trace.root.indent -= 1
|
||||
if self._notfound:
|
||||
errors = []
|
||||
for arg, exc in self._notfound:
|
||||
line = "(no name %r in any of %r)" % (arg, exc.args[0])
|
||||
errors.append("not found: %s\n%s" % (arg, line))
|
||||
# XXX: test this
|
||||
raise UsageError(*errors)
|
||||
if not genitems:
|
||||
return rep.result
|
||||
else:
|
||||
if rep.passed:
|
||||
for node in rep.result:
|
||||
self.items.extend(self.genitems(node))
|
||||
return items
|
||||
|
||||
def collect(self):
|
||||
for parts in self._initialparts:
|
||||
arg = "::".join(map(str, parts))
|
||||
self.trace("processing argument", arg)
|
||||
self.trace.root.indent += 1
|
||||
try:
|
||||
for x in self._collect(arg):
|
||||
yield x
|
||||
except NoMatch:
|
||||
# we are inside a make_report hook so
|
||||
# we cannot directly pass through the exception
|
||||
self._notfound.append((arg, sys.exc_info()[1]))
|
||||
|
||||
self.trace.root.indent -= 1
|
||||
|
||||
def _collect(self, arg):
|
||||
names = self._parsearg(arg)
|
||||
path = names.pop(0)
|
||||
if path.check(dir=1):
|
||||
assert not names, "invalid arg %r" % (arg,)
|
||||
for path in path.visit(fil=lambda x: x.check(file=1),
|
||||
rec=self._recurse, bf=True, sort=True):
|
||||
for x in self._collectfile(path):
|
||||
yield x
|
||||
else:
|
||||
assert path.check(file=1)
|
||||
for x in self.matchnodes(self._collectfile(path), names):
|
||||
yield x
|
||||
|
||||
def _collectfile(self, path):
|
||||
ihook = self.gethookproxy(path)
|
||||
if not self.isinitpath(path):
|
||||
if ihook.pytest_ignore_collect(path=path, config=self.config):
|
||||
return ()
|
||||
return ihook.pytest_collect_file(path=path, parent=self)
|
||||
|
||||
def _recurse(self, path):
|
||||
ihook = self.gethookproxy(path.dirpath())
|
||||
if ihook.pytest_ignore_collect(path=path, config=self.config):
|
||||
return
|
||||
for pat in self._norecursepatterns:
|
||||
if path.check(fnmatch=pat):
|
||||
return False
|
||||
ihook = self.gethookproxy(path)
|
||||
ihook.pytest_collect_directory(path=path, parent=self)
|
||||
return True
|
||||
|
||||
def _tryconvertpyarg(self, x):
|
||||
"""Convert a dotted module name to path.
|
||||
|
||||
"""
|
||||
import pkgutil
|
||||
try:
|
||||
loader = pkgutil.find_loader(x)
|
||||
except ImportError:
|
||||
return x
|
||||
if loader is None:
|
||||
return x
|
||||
# This method is sometimes invoked when AssertionRewritingHook, which
|
||||
# does not define a get_filename method, is already in place:
|
||||
try:
|
||||
path = loader.get_filename(x)
|
||||
except AttributeError:
|
||||
# Retrieve path from AssertionRewritingHook:
|
||||
path = loader.modules[x][0].co_filename
|
||||
if loader.is_package(x):
|
||||
path = os.path.dirname(path)
|
||||
return path
|
||||
|
||||
def _parsearg(self, arg):
|
||||
""" return (fspath, names) tuple after checking the file exists. """
|
||||
parts = str(arg).split("::")
|
||||
if self.config.option.pyargs:
|
||||
parts[0] = self._tryconvertpyarg(parts[0])
|
||||
relpath = parts[0].replace("/", os.sep)
|
||||
path = self.config.invocation_dir.join(relpath, abs=True)
|
||||
if not path.check():
|
||||
if self.config.option.pyargs:
|
||||
raise UsageError(
|
||||
"file or package not found: " + arg +
|
||||
" (missing __init__.py?)")
|
||||
else:
|
||||
raise UsageError("file not found: " + arg)
|
||||
parts[0] = path
|
||||
return parts
|
||||
|
||||
def matchnodes(self, matching, names):
|
||||
self.trace("matchnodes", matching, names)
|
||||
self.trace.root.indent += 1
|
||||
nodes = self._matchnodes(matching, names)
|
||||
num = len(nodes)
|
||||
self.trace("matchnodes finished -> ", num, "nodes")
|
||||
self.trace.root.indent -= 1
|
||||
if num == 0:
|
||||
raise NoMatch(matching, names[:1])
|
||||
return nodes
|
||||
|
||||
def _matchnodes(self, matching, names):
|
||||
if not matching or not names:
|
||||
return matching
|
||||
name = names[0]
|
||||
assert name
|
||||
nextnames = names[1:]
|
||||
resultnodes = []
|
||||
for node in matching:
|
||||
if isinstance(node, Item):
|
||||
if not names:
|
||||
resultnodes.append(node)
|
||||
continue
|
||||
assert isinstance(node, Collector)
|
||||
rep = collect_one_node(node)
|
||||
if rep.passed:
|
||||
has_matched = False
|
||||
for x in rep.result:
|
||||
# TODO: remove parametrized workaround once collection structure contains parametrization
|
||||
if x.name == name or x.name.split("[")[0] == name:
|
||||
resultnodes.extend(self.matchnodes([x], nextnames))
|
||||
has_matched = True
|
||||
# XXX accept IDs that don't have "()" for class instances
|
||||
if not has_matched and len(rep.result) == 1 and x.name == "()":
|
||||
nextnames.insert(0, name)
|
||||
resultnodes.extend(self.matchnodes([x], nextnames))
|
||||
else:
|
||||
# report collection failures here to avoid failing to run some test
|
||||
# specified in the command line because the module could not be
|
||||
# imported (#134)
|
||||
node.ihook.pytest_collectreport(report=rep)
|
||||
return resultnodes
|
||||
|
||||
def genitems(self, node):
|
||||
self.trace("genitems", node)
|
||||
if isinstance(node, Item):
|
||||
node.ihook.pytest_itemcollected(item=node)
|
||||
yield node
|
||||
else:
|
||||
assert isinstance(node, Collector)
|
||||
rep = collect_one_node(node)
|
||||
if rep.passed:
|
||||
for subnode in rep.result:
|
||||
for x in self.genitems(subnode):
|
||||
yield x
|
||||
node.ihook.pytest_collectreport(report=rep)
|
||||
465
_pytest/mark.py
465
_pytest/mark.py
@@ -1,465 +0,0 @@
|
||||
""" generic mechanism for marking and selecting python functions. """
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import inspect
|
||||
import warnings
|
||||
from collections import namedtuple
|
||||
from operator import attrgetter
|
||||
from .compat import imap
|
||||
from .deprecated import MARK_PARAMETERSET_UNPACKING
|
||||
|
||||
|
||||
def alias(name, warning=None):
|
||||
getter = attrgetter(name)
|
||||
|
||||
def warned(self):
|
||||
warnings.warn(warning, stacklevel=2)
|
||||
return getter(self)
|
||||
|
||||
return property(getter if warning is None else warned, doc='alias for ' + name)
|
||||
|
||||
|
||||
class ParameterSet(namedtuple('ParameterSet', 'values, marks, id')):
|
||||
@classmethod
|
||||
def param(cls, *values, **kw):
|
||||
marks = kw.pop('marks', ())
|
||||
if isinstance(marks, MarkDecorator):
|
||||
marks = marks,
|
||||
else:
|
||||
assert isinstance(marks, (tuple, list, set))
|
||||
|
||||
def param_extract_id(id=None):
|
||||
return id
|
||||
|
||||
id = param_extract_id(**kw)
|
||||
return cls(values, marks, id)
|
||||
|
||||
@classmethod
|
||||
def extract_from(cls, parameterset, legacy_force_tuple=False):
|
||||
"""
|
||||
:param parameterset:
|
||||
a legacy style parameterset that may or may not be a tuple,
|
||||
and may or may not be wrapped into a mess of mark objects
|
||||
|
||||
:param legacy_force_tuple:
|
||||
enforce tuple wrapping so single argument tuple values
|
||||
don't get decomposed and break tests
|
||||
|
||||
"""
|
||||
|
||||
if isinstance(parameterset, cls):
|
||||
return parameterset
|
||||
if not isinstance(parameterset, MarkDecorator) and legacy_force_tuple:
|
||||
return cls.param(parameterset)
|
||||
|
||||
newmarks = []
|
||||
argval = parameterset
|
||||
while isinstance(argval, MarkDecorator):
|
||||
newmarks.append(MarkDecorator(Mark(
|
||||
argval.markname, argval.args[:-1], argval.kwargs)))
|
||||
argval = argval.args[-1]
|
||||
assert not isinstance(argval, ParameterSet)
|
||||
if legacy_force_tuple:
|
||||
argval = argval,
|
||||
|
||||
if newmarks:
|
||||
warnings.warn(MARK_PARAMETERSET_UNPACKING)
|
||||
|
||||
return cls(argval, marks=newmarks, id=None)
|
||||
|
||||
@property
|
||||
def deprecated_arg_dict(self):
|
||||
return dict((mark.name, mark) for mark in self.marks)
|
||||
|
||||
|
||||
class MarkerError(Exception):
|
||||
|
||||
"""Error in use of a pytest marker/attribute."""
|
||||
|
||||
|
||||
def param(*values, **kw):
|
||||
return ParameterSet.param(*values, **kw)
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
group = parser.getgroup("general")
|
||||
group._addoption(
|
||||
'-k',
|
||||
action="store", dest="keyword", default='', metavar="EXPRESSION",
|
||||
help="only run tests which match the given substring expression. "
|
||||
"An expression is a python evaluatable expression "
|
||||
"where all names are substring-matched against test names "
|
||||
"and their parent classes. Example: -k 'test_method or test_"
|
||||
"other' matches all test functions and classes whose name "
|
||||
"contains 'test_method' or 'test_other', while -k 'not test_method' "
|
||||
"matches those that don't contain 'test_method' in their names. "
|
||||
"Additionally keywords are matched to classes and functions "
|
||||
"containing extra names in their 'extra_keyword_matches' set, "
|
||||
"as well as functions which have names assigned directly to them."
|
||||
)
|
||||
|
||||
group._addoption(
|
||||
"-m",
|
||||
action="store", dest="markexpr", default="", metavar="MARKEXPR",
|
||||
help="only run tests matching given mark expression. "
|
||||
"example: -m 'mark1 and not mark2'."
|
||||
)
|
||||
|
||||
group.addoption(
|
||||
"--markers", action="store_true",
|
||||
help="show markers (builtin, plugin and per-project ones)."
|
||||
)
|
||||
|
||||
parser.addini("markers", "markers for test functions", 'linelist')
|
||||
|
||||
|
||||
def pytest_cmdline_main(config):
|
||||
import _pytest.config
|
||||
if config.option.markers:
|
||||
config._do_configure()
|
||||
tw = _pytest.config.create_terminal_writer(config)
|
||||
for line in config.getini("markers"):
|
||||
name, rest = line.split(":", 1)
|
||||
tw.write("@pytest.mark.%s:" % name, bold=True)
|
||||
tw.line(rest)
|
||||
tw.line()
|
||||
config._ensure_unconfigure()
|
||||
return 0
|
||||
|
||||
|
||||
pytest_cmdline_main.tryfirst = True
|
||||
|
||||
|
||||
def pytest_collection_modifyitems(items, config):
|
||||
keywordexpr = config.option.keyword.lstrip()
|
||||
matchexpr = config.option.markexpr
|
||||
if not keywordexpr and not matchexpr:
|
||||
return
|
||||
# pytest used to allow "-" for negating
|
||||
# but today we just allow "-" at the beginning, use "not" instead
|
||||
# we probably remove "-" altogether soon
|
||||
if keywordexpr.startswith("-"):
|
||||
keywordexpr = "not " + keywordexpr[1:]
|
||||
selectuntil = False
|
||||
if keywordexpr[-1:] == ":":
|
||||
selectuntil = True
|
||||
keywordexpr = keywordexpr[:-1]
|
||||
|
||||
remaining = []
|
||||
deselected = []
|
||||
for colitem in items:
|
||||
if keywordexpr and not matchkeyword(colitem, keywordexpr):
|
||||
deselected.append(colitem)
|
||||
else:
|
||||
if selectuntil:
|
||||
keywordexpr = None
|
||||
if matchexpr:
|
||||
if not matchmark(colitem, matchexpr):
|
||||
deselected.append(colitem)
|
||||
continue
|
||||
remaining.append(colitem)
|
||||
|
||||
if deselected:
|
||||
config.hook.pytest_deselected(items=deselected)
|
||||
items[:] = remaining
|
||||
|
||||
|
||||
class MarkMapping:
|
||||
"""Provides a local mapping for markers where item access
|
||||
resolves to True if the marker is present. """
|
||||
|
||||
def __init__(self, keywords):
|
||||
mymarks = set()
|
||||
for key, value in keywords.items():
|
||||
if isinstance(value, MarkInfo) or isinstance(value, MarkDecorator):
|
||||
mymarks.add(key)
|
||||
self._mymarks = mymarks
|
||||
|
||||
def __getitem__(self, name):
|
||||
return name in self._mymarks
|
||||
|
||||
|
||||
class KeywordMapping:
|
||||
"""Provides a local mapping for keywords.
|
||||
Given a list of names, map any substring of one of these names to True.
|
||||
"""
|
||||
|
||||
def __init__(self, names):
|
||||
self._names = names
|
||||
|
||||
def __getitem__(self, subname):
|
||||
for name in self._names:
|
||||
if subname in name:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def matchmark(colitem, markexpr):
|
||||
"""Tries to match on any marker names, attached to the given colitem."""
|
||||
return eval(markexpr, {}, MarkMapping(colitem.keywords))
|
||||
|
||||
|
||||
def matchkeyword(colitem, keywordexpr):
|
||||
"""Tries to match given keyword expression to given collector item.
|
||||
|
||||
Will match on the name of colitem, including the names of its parents.
|
||||
Only matches names of items which are either a :class:`Class` or a
|
||||
:class:`Function`.
|
||||
Additionally, matches on names in the 'extra_keyword_matches' set of
|
||||
any item, as well as names directly assigned to test functions.
|
||||
"""
|
||||
mapped_names = set()
|
||||
|
||||
# Add the names of the current item and any parent items
|
||||
import pytest
|
||||
for item in colitem.listchain():
|
||||
if not isinstance(item, pytest.Instance):
|
||||
mapped_names.add(item.name)
|
||||
|
||||
# Add the names added as extra keywords to current or parent items
|
||||
for name in colitem.listextrakeywords():
|
||||
mapped_names.add(name)
|
||||
|
||||
# Add the names attached to the current function through direct assignment
|
||||
if hasattr(colitem, 'function'):
|
||||
for name in colitem.function.__dict__:
|
||||
mapped_names.add(name)
|
||||
|
||||
mapping = KeywordMapping(mapped_names)
|
||||
if " " not in keywordexpr:
|
||||
# special case to allow for simple "-k pass" and "-k 1.3"
|
||||
return mapping[keywordexpr]
|
||||
elif keywordexpr.startswith("not ") and " " not in keywordexpr[4:]:
|
||||
return not mapping[keywordexpr[4:]]
|
||||
return eval(keywordexpr, {}, mapping)
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
config._old_mark_config = MARK_GEN._config
|
||||
if config.option.strict:
|
||||
MARK_GEN._config = config
|
||||
|
||||
|
||||
def pytest_unconfigure(config):
|
||||
MARK_GEN._config = getattr(config, '_old_mark_config', None)
|
||||
|
||||
|
||||
class MarkGenerator:
|
||||
""" Factory for :class:`MarkDecorator` objects - exposed as
|
||||
a ``pytest.mark`` singleton instance. Example::
|
||||
|
||||
import pytest
|
||||
@pytest.mark.slowtest
|
||||
def test_function():
|
||||
pass
|
||||
|
||||
will set a 'slowtest' :class:`MarkInfo` object
|
||||
on the ``test_function`` object. """
|
||||
_config = None
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name[0] == "_":
|
||||
raise AttributeError("Marker name must NOT start with underscore")
|
||||
if self._config is not None:
|
||||
self._check(name)
|
||||
return MarkDecorator(Mark(name, (), {}))
|
||||
|
||||
def _check(self, name):
|
||||
try:
|
||||
if name in self._markers:
|
||||
return
|
||||
except AttributeError:
|
||||
pass
|
||||
self._markers = values = set()
|
||||
for line in self._config.getini("markers"):
|
||||
marker, _ = line.split(":", 1)
|
||||
marker = marker.rstrip()
|
||||
x = marker.split("(", 1)[0]
|
||||
values.add(x)
|
||||
if name not in self._markers:
|
||||
raise AttributeError("%r not a registered marker" % (name,))
|
||||
|
||||
|
||||
def istestfunc(func):
|
||||
return hasattr(func, "__call__") and \
|
||||
getattr(func, "__name__", "<lambda>") != "<lambda>"
|
||||
|
||||
|
||||
class MarkDecorator:
|
||||
""" A decorator for test functions and test classes. When applied
|
||||
it will create :class:`MarkInfo` objects which may be
|
||||
:ref:`retrieved by hooks as item keywords <excontrolskip>`.
|
||||
MarkDecorator instances are often created like this::
|
||||
|
||||
mark1 = pytest.mark.NAME # simple MarkDecorator
|
||||
mark2 = pytest.mark.NAME(name1=value) # parametrized MarkDecorator
|
||||
|
||||
and can then be applied as decorators to test functions::
|
||||
|
||||
@mark2
|
||||
def test_function():
|
||||
pass
|
||||
|
||||
When a MarkDecorator instance is called it does the following:
|
||||
1. If called with a single class as its only positional argument and no
|
||||
additional keyword arguments, it attaches itself to the class so it
|
||||
gets applied automatically to all test cases found in that class.
|
||||
2. If called with a single function as its only positional argument and
|
||||
no additional keyword arguments, it attaches a MarkInfo object to the
|
||||
function, containing all the arguments already stored internally in
|
||||
the MarkDecorator.
|
||||
3. When called in any other case, it performs a 'fake construction' call,
|
||||
i.e. it returns a new MarkDecorator instance with the original
|
||||
MarkDecorator's content updated with the arguments passed to this
|
||||
call.
|
||||
|
||||
Note: The rules above prevent MarkDecorator objects from storing only a
|
||||
single function or class reference as their positional argument with no
|
||||
additional keyword or positional arguments.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, mark):
|
||||
assert isinstance(mark, Mark), repr(mark)
|
||||
self.mark = mark
|
||||
|
||||
name = alias('mark.name')
|
||||
args = alias('mark.args')
|
||||
kwargs = alias('mark.kwargs')
|
||||
|
||||
@property
|
||||
def markname(self):
|
||||
return self.name # for backward-compat (2.4.1 had this attr)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.mark == other.mark if isinstance(other, MarkDecorator) else False
|
||||
|
||||
def __repr__(self):
|
||||
return "<MarkDecorator %r>" % (self.mark,)
|
||||
|
||||
def with_args(self, *args, **kwargs):
|
||||
""" return a MarkDecorator with extra arguments added
|
||||
|
||||
unlike call this can be used even if the sole argument is a callable/class
|
||||
|
||||
:return: MarkDecorator
|
||||
"""
|
||||
|
||||
mark = Mark(self.name, args, kwargs)
|
||||
return self.__class__(self.mark.combined_with(mark))
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
""" if passed a single callable argument: decorate it with mark info.
|
||||
otherwise add *args/**kwargs in-place to mark information. """
|
||||
if args and not kwargs:
|
||||
func = args[0]
|
||||
is_class = inspect.isclass(func)
|
||||
if len(args) == 1 and (istestfunc(func) or is_class):
|
||||
if is_class:
|
||||
store_mark(func, self.mark)
|
||||
else:
|
||||
store_legacy_markinfo(func, self.mark)
|
||||
store_mark(func, self.mark)
|
||||
return func
|
||||
return self.with_args(*args, **kwargs)
|
||||
|
||||
|
||||
def get_unpacked_marks(obj):
|
||||
"""
|
||||
obtain the unpacked marks that are stored on a object
|
||||
"""
|
||||
mark_list = getattr(obj, 'pytestmark', [])
|
||||
|
||||
if not isinstance(mark_list, list):
|
||||
mark_list = [mark_list]
|
||||
return [
|
||||
getattr(mark, 'mark', mark) # unpack MarkDecorator
|
||||
for mark in mark_list
|
||||
]
|
||||
|
||||
|
||||
def store_mark(obj, mark):
|
||||
"""store a Mark on a object
|
||||
this is used to implement the Mark declarations/decorators correctly
|
||||
"""
|
||||
assert isinstance(mark, Mark), mark
|
||||
# always reassign name to avoid updating pytestmark
|
||||
# in a reference that was only borrowed
|
||||
obj.pytestmark = get_unpacked_marks(obj) + [mark]
|
||||
|
||||
|
||||
def store_legacy_markinfo(func, mark):
|
||||
"""create the legacy MarkInfo objects and put them onto the function
|
||||
"""
|
||||
if not isinstance(mark, Mark):
|
||||
raise TypeError("got {mark!r} instead of a Mark".format(mark=mark))
|
||||
holder = getattr(func, mark.name, None)
|
||||
if holder is None:
|
||||
holder = MarkInfo(mark)
|
||||
setattr(func, mark.name, holder)
|
||||
else:
|
||||
holder.add_mark(mark)
|
||||
|
||||
|
||||
class Mark(namedtuple('Mark', 'name, args, kwargs')):
|
||||
|
||||
def combined_with(self, other):
|
||||
assert self.name == other.name
|
||||
return Mark(
|
||||
self.name, self.args + other.args,
|
||||
dict(self.kwargs, **other.kwargs))
|
||||
|
||||
|
||||
class MarkInfo(object):
|
||||
""" Marking object created by :class:`MarkDecorator` instances. """
|
||||
|
||||
def __init__(self, mark):
|
||||
assert isinstance(mark, Mark), repr(mark)
|
||||
self.combined = mark
|
||||
self._marks = [mark]
|
||||
|
||||
name = alias('combined.name')
|
||||
args = alias('combined.args')
|
||||
kwargs = alias('combined.kwargs')
|
||||
|
||||
def __repr__(self):
|
||||
return "<MarkInfo {0!r}>".format(self.combined)
|
||||
|
||||
def add_mark(self, mark):
|
||||
""" add a MarkInfo with the given args and kwargs. """
|
||||
self._marks.append(mark)
|
||||
self.combined = self.combined.combined_with(mark)
|
||||
|
||||
def __iter__(self):
|
||||
""" yield MarkInfo objects each relating to a marking-call. """
|
||||
return imap(MarkInfo, self._marks)
|
||||
|
||||
|
||||
MARK_GEN = MarkGenerator()
|
||||
|
||||
|
||||
def _marked(func, mark):
|
||||
""" Returns True if :func: is already marked with :mark:, False otherwise.
|
||||
This can happen if marker is applied to class and the test file is
|
||||
invoked more than once.
|
||||
"""
|
||||
try:
|
||||
func_mark = getattr(func, mark.name)
|
||||
except AttributeError:
|
||||
return False
|
||||
return mark.args == func_mark.args and mark.kwargs == func_mark.kwargs
|
||||
|
||||
|
||||
def transfer_markers(funcobj, cls, mod):
|
||||
"""
|
||||
this function transfers class level markers and module level markers
|
||||
into function level markinfo objects
|
||||
|
||||
this is the main reason why marks are so broken
|
||||
the resolution will involve phasing out function level MarkInfo objects
|
||||
|
||||
"""
|
||||
for obj in (cls, mod):
|
||||
for mark in get_unpacked_marks(obj):
|
||||
if not _marked(funcobj, mark):
|
||||
store_legacy_markinfo(funcobj, mark)
|
||||
@@ -1,37 +0,0 @@
|
||||
SEP = "/"
|
||||
|
||||
|
||||
def _splitnode(nodeid):
|
||||
"""Split a nodeid into constituent 'parts'.
|
||||
|
||||
Node IDs are strings, and can be things like:
|
||||
''
|
||||
'testing/code'
|
||||
'testing/code/test_excinfo.py'
|
||||
'testing/code/test_excinfo.py::TestFormattedExcinfo::()'
|
||||
|
||||
Return values are lists e.g.
|
||||
[]
|
||||
['testing', 'code']
|
||||
['testing', 'code', 'test_excinfo.py']
|
||||
['testing', 'code', 'test_excinfo.py', 'TestFormattedExcinfo', '()']
|
||||
"""
|
||||
if nodeid == '':
|
||||
# If there is no root node at all, return an empty list so the caller's logic can remain sane
|
||||
return []
|
||||
parts = nodeid.split(SEP)
|
||||
# Replace single last element 'test_foo.py::Bar::()' with multiple elements 'test_foo.py', 'Bar', '()'
|
||||
parts[-1:] = parts[-1].split("::")
|
||||
return parts
|
||||
|
||||
|
||||
def ischildnode(baseid, nodeid):
|
||||
"""Return True if the nodeid is a child node of the baseid.
|
||||
|
||||
E.g. 'foo/bar::Baz::()' is a child of 'foo', 'foo/bar' and 'foo/bar::Baz', but not of 'foo/blorp'
|
||||
"""
|
||||
base_parts = _splitnode(baseid)
|
||||
node_parts = _splitnode(nodeid)
|
||||
if len(node_parts) < len(base_parts):
|
||||
return False
|
||||
return node_parts[:len(base_parts)] == base_parts
|
||||
@@ -1,372 +0,0 @@
|
||||
""" support for skip/xfail functions and markers. """
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
import py
|
||||
from _pytest.config import hookimpl
|
||||
from _pytest.mark import MarkInfo, MarkDecorator
|
||||
from _pytest.outcomes import fail, skip, xfail, TEST_OUTCOME
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
group = parser.getgroup("general")
|
||||
group.addoption('--runxfail',
|
||||
action="store_true", dest="runxfail", default=False,
|
||||
help="run tests even if they are marked xfail")
|
||||
|
||||
parser.addini("xfail_strict", "default for the strict parameter of xfail "
|
||||
"markers when not given explicitly (default: "
|
||||
"False)",
|
||||
default=False,
|
||||
type="bool")
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
if config.option.runxfail:
|
||||
# yay a hack
|
||||
import pytest
|
||||
old = pytest.xfail
|
||||
config._cleanup.append(lambda: setattr(pytest, "xfail", old))
|
||||
|
||||
def nop(*args, **kwargs):
|
||||
pass
|
||||
|
||||
nop.Exception = xfail.Exception
|
||||
setattr(pytest, "xfail", nop)
|
||||
|
||||
config.addinivalue_line("markers",
|
||||
"skip(reason=None): skip the given test function with an optional reason. "
|
||||
"Example: skip(reason=\"no way of currently testing this\") skips the "
|
||||
"test."
|
||||
)
|
||||
config.addinivalue_line("markers",
|
||||
"skipif(condition): skip the given test function if eval(condition) "
|
||||
"results in a True value. Evaluation happens within the "
|
||||
"module global context. Example: skipif('sys.platform == \"win32\"') "
|
||||
"skips the test if we are on the win32 platform. see "
|
||||
"http://pytest.org/latest/skipping.html"
|
||||
)
|
||||
config.addinivalue_line("markers",
|
||||
"xfail(condition, reason=None, run=True, raises=None, strict=False): "
|
||||
"mark the test function as an expected failure if eval(condition) "
|
||||
"has a True value. Optionally specify a reason for better reporting "
|
||||
"and run=False if you don't even want to execute the test function. "
|
||||
"If only specific exception(s) are expected, you can list them in "
|
||||
"raises, and if the test fails in other ways, it will be reported as "
|
||||
"a true failure. See http://pytest.org/latest/skipping.html"
|
||||
)
|
||||
|
||||
|
||||
class MarkEvaluator:
|
||||
def __init__(self, item, name):
|
||||
self.item = item
|
||||
self.name = name
|
||||
|
||||
@property
|
||||
def holder(self):
|
||||
return self.item.keywords.get(self.name)
|
||||
|
||||
def __bool__(self):
|
||||
return bool(self.holder)
|
||||
__nonzero__ = __bool__
|
||||
|
||||
def wasvalid(self):
|
||||
return not hasattr(self, 'exc')
|
||||
|
||||
def invalidraise(self, exc):
|
||||
raises = self.get('raises')
|
||||
if not raises:
|
||||
return
|
||||
return not isinstance(exc, raises)
|
||||
|
||||
def istrue(self):
|
||||
try:
|
||||
return self._istrue()
|
||||
except TEST_OUTCOME:
|
||||
self.exc = sys.exc_info()
|
||||
if isinstance(self.exc[1], SyntaxError):
|
||||
msg = [" " * (self.exc[1].offset + 4) + "^", ]
|
||||
msg.append("SyntaxError: invalid syntax")
|
||||
else:
|
||||
msg = traceback.format_exception_only(*self.exc[:2])
|
||||
fail("Error evaluating %r expression\n"
|
||||
" %s\n"
|
||||
"%s"
|
||||
% (self.name, self.expr, "\n".join(msg)),
|
||||
pytrace=False)
|
||||
|
||||
def _getglobals(self):
|
||||
d = {'os': os, 'sys': sys, 'config': self.item.config}
|
||||
if hasattr(self.item, 'obj'):
|
||||
d.update(self.item.obj.__globals__)
|
||||
return d
|
||||
|
||||
def _istrue(self):
|
||||
if hasattr(self, 'result'):
|
||||
return self.result
|
||||
if self.holder:
|
||||
if self.holder.args or 'condition' in self.holder.kwargs:
|
||||
self.result = False
|
||||
# "holder" might be a MarkInfo or a MarkDecorator; only
|
||||
# MarkInfo keeps track of all parameters it received in an
|
||||
# _arglist attribute
|
||||
marks = getattr(self.holder, '_marks', None) \
|
||||
or [self.holder.mark]
|
||||
for _, args, kwargs in marks:
|
||||
if 'condition' in kwargs:
|
||||
args = (kwargs['condition'],)
|
||||
for expr in args:
|
||||
self.expr = expr
|
||||
if isinstance(expr, py.builtin._basestring):
|
||||
d = self._getglobals()
|
||||
result = cached_eval(self.item.config, expr, d)
|
||||
else:
|
||||
if "reason" not in kwargs:
|
||||
# XXX better be checked at collection time
|
||||
msg = "you need to specify reason=STRING " \
|
||||
"when using booleans as conditions."
|
||||
fail(msg)
|
||||
result = bool(expr)
|
||||
if result:
|
||||
self.result = True
|
||||
self.reason = kwargs.get('reason', None)
|
||||
self.expr = expr
|
||||
return self.result
|
||||
else:
|
||||
self.result = True
|
||||
return getattr(self, 'result', False)
|
||||
|
||||
def get(self, attr, default=None):
|
||||
return self.holder.kwargs.get(attr, default)
|
||||
|
||||
def getexplanation(self):
|
||||
expl = getattr(self, 'reason', None) or self.get('reason', None)
|
||||
if not expl:
|
||||
if not hasattr(self, 'expr'):
|
||||
return ""
|
||||
else:
|
||||
return "condition: " + str(self.expr)
|
||||
return expl
|
||||
|
||||
|
||||
@hookimpl(tryfirst=True)
|
||||
def pytest_runtest_setup(item):
|
||||
# Check if skip or skipif are specified as pytest marks
|
||||
|
||||
skipif_info = item.keywords.get('skipif')
|
||||
if isinstance(skipif_info, (MarkInfo, MarkDecorator)):
|
||||
eval_skipif = MarkEvaluator(item, 'skipif')
|
||||
if eval_skipif.istrue():
|
||||
item._evalskip = eval_skipif
|
||||
skip(eval_skipif.getexplanation())
|
||||
|
||||
skip_info = item.keywords.get('skip')
|
||||
if isinstance(skip_info, (MarkInfo, MarkDecorator)):
|
||||
item._evalskip = True
|
||||
if 'reason' in skip_info.kwargs:
|
||||
skip(skip_info.kwargs['reason'])
|
||||
elif skip_info.args:
|
||||
skip(skip_info.args[0])
|
||||
else:
|
||||
skip("unconditional skip")
|
||||
|
||||
item._evalxfail = MarkEvaluator(item, 'xfail')
|
||||
check_xfail_no_run(item)
|
||||
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
def pytest_pyfunc_call(pyfuncitem):
|
||||
check_xfail_no_run(pyfuncitem)
|
||||
outcome = yield
|
||||
passed = outcome.excinfo is None
|
||||
if passed:
|
||||
check_strict_xfail(pyfuncitem)
|
||||
|
||||
|
||||
def check_xfail_no_run(item):
|
||||
"""check xfail(run=False)"""
|
||||
if not item.config.option.runxfail:
|
||||
evalxfail = item._evalxfail
|
||||
if evalxfail.istrue():
|
||||
if not evalxfail.get('run', True):
|
||||
xfail("[NOTRUN] " + evalxfail.getexplanation())
|
||||
|
||||
|
||||
def check_strict_xfail(pyfuncitem):
|
||||
"""check xfail(strict=True) for the given PASSING test"""
|
||||
evalxfail = pyfuncitem._evalxfail
|
||||
if evalxfail.istrue():
|
||||
strict_default = pyfuncitem.config.getini('xfail_strict')
|
||||
is_strict_xfail = evalxfail.get('strict', strict_default)
|
||||
if is_strict_xfail:
|
||||
del pyfuncitem._evalxfail
|
||||
explanation = evalxfail.getexplanation()
|
||||
fail('[XPASS(strict)] ' + explanation, pytrace=False)
|
||||
|
||||
|
||||
@hookimpl(hookwrapper=True)
|
||||
def pytest_runtest_makereport(item, call):
|
||||
outcome = yield
|
||||
rep = outcome.get_result()
|
||||
evalxfail = getattr(item, '_evalxfail', None)
|
||||
evalskip = getattr(item, '_evalskip', None)
|
||||
# unitttest special case, see setting of _unexpectedsuccess
|
||||
if hasattr(item, '_unexpectedsuccess') and rep.when == "call":
|
||||
from _pytest.compat import _is_unittest_unexpected_success_a_failure
|
||||
if item._unexpectedsuccess:
|
||||
rep.longrepr = "Unexpected success: {0}".format(item._unexpectedsuccess)
|
||||
else:
|
||||
rep.longrepr = "Unexpected success"
|
||||
if _is_unittest_unexpected_success_a_failure():
|
||||
rep.outcome = "failed"
|
||||
else:
|
||||
rep.outcome = "passed"
|
||||
rep.wasxfail = rep.longrepr
|
||||
elif item.config.option.runxfail:
|
||||
pass # don't interefere
|
||||
elif call.excinfo and call.excinfo.errisinstance(xfail.Exception):
|
||||
rep.wasxfail = "reason: " + call.excinfo.value.msg
|
||||
rep.outcome = "skipped"
|
||||
elif evalxfail and not rep.skipped and evalxfail.wasvalid() and \
|
||||
evalxfail.istrue():
|
||||
if call.excinfo:
|
||||
if evalxfail.invalidraise(call.excinfo.value):
|
||||
rep.outcome = "failed"
|
||||
else:
|
||||
rep.outcome = "skipped"
|
||||
rep.wasxfail = evalxfail.getexplanation()
|
||||
elif call.when == "call":
|
||||
strict_default = item.config.getini('xfail_strict')
|
||||
is_strict_xfail = evalxfail.get('strict', strict_default)
|
||||
explanation = evalxfail.getexplanation()
|
||||
if is_strict_xfail:
|
||||
rep.outcome = "failed"
|
||||
rep.longrepr = "[XPASS(strict)] {0}".format(explanation)
|
||||
else:
|
||||
rep.outcome = "passed"
|
||||
rep.wasxfail = explanation
|
||||
elif evalskip is not None and rep.skipped and type(rep.longrepr) is tuple:
|
||||
# skipped by mark.skipif; change the location of the failure
|
||||
# to point to the item definition, otherwise it will display
|
||||
# the location of where the skip exception was raised within pytest
|
||||
filename, line, reason = rep.longrepr
|
||||
filename, line = item.location[:2]
|
||||
rep.longrepr = filename, line, reason
|
||||
|
||||
# called by terminalreporter progress reporting
|
||||
|
||||
|
||||
def pytest_report_teststatus(report):
|
||||
if hasattr(report, "wasxfail"):
|
||||
if report.skipped:
|
||||
return "xfailed", "x", "xfail"
|
||||
elif report.passed:
|
||||
return "xpassed", "X", ("XPASS", {'yellow': True})
|
||||
|
||||
# called by the terminalreporter instance/plugin
|
||||
|
||||
|
||||
def pytest_terminal_summary(terminalreporter):
|
||||
tr = terminalreporter
|
||||
if not tr.reportchars:
|
||||
# for name in "xfailed skipped failed xpassed":
|
||||
# if not tr.stats.get(name, 0):
|
||||
# tr.write_line("HINT: use '-r' option to see extra "
|
||||
# "summary info about tests")
|
||||
# break
|
||||
return
|
||||
|
||||
lines = []
|
||||
for char in tr.reportchars:
|
||||
if char == "x":
|
||||
show_xfailed(terminalreporter, lines)
|
||||
elif char == "X":
|
||||
show_xpassed(terminalreporter, lines)
|
||||
elif char in "fF":
|
||||
show_simple(terminalreporter, lines, 'failed', "FAIL %s")
|
||||
elif char in "sS":
|
||||
show_skipped(terminalreporter, lines)
|
||||
elif char == "E":
|
||||
show_simple(terminalreporter, lines, 'error', "ERROR %s")
|
||||
elif char == 'p':
|
||||
show_simple(terminalreporter, lines, 'passed', "PASSED %s")
|
||||
|
||||
if lines:
|
||||
tr._tw.sep("=", "short test summary info")
|
||||
for line in lines:
|
||||
tr._tw.line(line)
|
||||
|
||||
|
||||
def show_simple(terminalreporter, lines, stat, format):
|
||||
failed = terminalreporter.stats.get(stat)
|
||||
if failed:
|
||||
for rep in failed:
|
||||
pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid)
|
||||
lines.append(format % (pos,))
|
||||
|
||||
|
||||
def show_xfailed(terminalreporter, lines):
|
||||
xfailed = terminalreporter.stats.get("xfailed")
|
||||
if xfailed:
|
||||
for rep in xfailed:
|
||||
pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid)
|
||||
reason = rep.wasxfail
|
||||
lines.append("XFAIL %s" % (pos,))
|
||||
if reason:
|
||||
lines.append(" " + str(reason))
|
||||
|
||||
|
||||
def show_xpassed(terminalreporter, lines):
|
||||
xpassed = terminalreporter.stats.get("xpassed")
|
||||
if xpassed:
|
||||
for rep in xpassed:
|
||||
pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid)
|
||||
reason = rep.wasxfail
|
||||
lines.append("XPASS %s %s" % (pos, reason))
|
||||
|
||||
|
||||
def cached_eval(config, expr, d):
|
||||
if not hasattr(config, '_evalcache'):
|
||||
config._evalcache = {}
|
||||
try:
|
||||
return config._evalcache[expr]
|
||||
except KeyError:
|
||||
import _pytest._code
|
||||
exprcode = _pytest._code.compile(expr, mode="eval")
|
||||
config._evalcache[expr] = x = eval(exprcode, d)
|
||||
return x
|
||||
|
||||
|
||||
def folded_skips(skipped):
|
||||
d = {}
|
||||
for event in skipped:
|
||||
key = event.longrepr
|
||||
assert len(key) == 3, (event, key)
|
||||
d.setdefault(key, []).append(event)
|
||||
values = []
|
||||
for key, events in d.items():
|
||||
values.append((len(events),) + key)
|
||||
return values
|
||||
|
||||
|
||||
def show_skipped(terminalreporter, lines):
|
||||
tr = terminalreporter
|
||||
skipped = tr.stats.get('skipped', [])
|
||||
if skipped:
|
||||
# if not tr.hasopt('skipped'):
|
||||
# tr.write_line(
|
||||
# "%d skipped tests, specify -rs for more info" %
|
||||
# len(skipped))
|
||||
# return
|
||||
fskips = folded_skips(skipped)
|
||||
if fskips:
|
||||
# tr.write_sep("_", "skipped test summary")
|
||||
for num, fspath, lineno, reason in fskips:
|
||||
if reason.startswith("Skipped: "):
|
||||
reason = reason[9:]
|
||||
lines.append(
|
||||
"SKIP [%d] %s:%d: %s" %
|
||||
(num, fspath, lineno + 1, reason))
|
||||
@@ -1,13 +0,0 @@
|
||||
This directory vendors the `pluggy` module.
|
||||
|
||||
For a more detailed discussion for the reasons to vendoring this
|
||||
package, please see [this issue](https://github.com/pytest-dev/pytest/issues/944).
|
||||
|
||||
To update the current version, execute:
|
||||
|
||||
```
|
||||
$ pip install -U pluggy==<version> --no-compile --target=_pytest/vendored_packages
|
||||
```
|
||||
|
||||
And commit the modified files. The `pluggy-<version>.dist-info` directory
|
||||
created by `pip` should be added as well.
|
||||
@@ -1,11 +0,0 @@
|
||||
|
||||
Plugin registration and hook calling for Python
|
||||
===============================================
|
||||
|
||||
This is the plugin manager as used by pytest but stripped
|
||||
of pytest specific details.
|
||||
|
||||
During the 0.x series this plugin does not have much documentation
|
||||
except extensive docstrings in the pluggy.py module.
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
pip
|
||||
@@ -1,22 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 holger krekel (rather uses bitbucket/hpk42)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
Metadata-Version: 2.0
|
||||
Name: pluggy
|
||||
Version: 0.4.0
|
||||
Summary: plugin and hook calling mechanisms for python
|
||||
Home-page: https://github.com/pytest-dev/pluggy
|
||||
Author: Holger Krekel
|
||||
Author-email: holger at merlinux.eu
|
||||
License: MIT license
|
||||
Platform: unix
|
||||
Platform: linux
|
||||
Platform: osx
|
||||
Platform: win32
|
||||
Classifier: Development Status :: 4 - Beta
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Operating System :: POSIX
|
||||
Classifier: Operating System :: Microsoft :: Windows
|
||||
Classifier: Operating System :: MacOS :: MacOS X
|
||||
Classifier: Topic :: Software Development :: Testing
|
||||
Classifier: Topic :: Software Development :: Libraries
|
||||
Classifier: Topic :: Utilities
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.3
|
||||
Classifier: Programming Language :: Python :: 3.4
|
||||
Classifier: Programming Language :: Python :: 3.5
|
||||
|
||||
|
||||
Plugin registration and hook calling for Python
|
||||
===============================================
|
||||
|
||||
This is the plugin manager as used by pytest but stripped
|
||||
of pytest specific details.
|
||||
|
||||
During the 0.x series this plugin does not have much documentation
|
||||
except extensive docstrings in the pluggy.py module.
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
pluggy.py,sha256=u0oG9cv-oLOkNvEBlwnnu8pp1AyxpoERgUO00S3rvpQ,31543
|
||||
pluggy-0.4.0.dist-info/DESCRIPTION.rst,sha256=ltvjkFd40LW_xShthp6RRVM6OB_uACYDFR3kTpKw7o4,307
|
||||
pluggy-0.4.0.dist-info/LICENSE.txt,sha256=ruwhUOyV1HgE9F35JVL9BCZ9vMSALx369I4xq9rhpkM,1134
|
||||
pluggy-0.4.0.dist-info/METADATA,sha256=pe2hbsqKFaLHC6wAQPpFPn0KlpcPfLBe_BnS4O70bfk,1364
|
||||
pluggy-0.4.0.dist-info/RECORD,,
|
||||
pluggy-0.4.0.dist-info/WHEEL,sha256=9Z5Xm-eel1bTS7e6ogYiKz0zmPEqDwIypurdHN1hR40,116
|
||||
pluggy-0.4.0.dist-info/metadata.json,sha256=T3go5L2qOa_-H-HpCZi3EoVKb8sZ3R-fOssbkWo2nvM,1119
|
||||
pluggy-0.4.0.dist-info/top_level.txt,sha256=xKSCRhai-v9MckvMuWqNz16c1tbsmOggoMSwTgcpYHE,7
|
||||
pluggy-0.4.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
@@ -1,6 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.29.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py2-none-any
|
||||
Tag: py3-none-any
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: POSIX", "Operating System :: Microsoft :: Windows", "Operating System :: MacOS :: MacOS X", "Topic :: Software Development :: Testing", "Topic :: Software Development :: Libraries", "Topic :: Utilities", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5"], "extensions": {"python.details": {"contacts": [{"email": "holger at merlinux.eu", "name": "Holger Krekel", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}, "project_urls": {"Home": "https://github.com/pytest-dev/pluggy"}}}, "generator": "bdist_wheel (0.29.0)", "license": "MIT license", "metadata_version": "2.0", "name": "pluggy", "platform": "unix", "summary": "plugin and hook calling mechanisms for python", "version": "0.4.0"}
|
||||
@@ -1 +0,0 @@
|
||||
pluggy
|
||||
@@ -1,802 +0,0 @@
|
||||
"""
|
||||
PluginManager, basic initialization and tracing.
|
||||
|
||||
pluggy is the cristallized core of plugin management as used
|
||||
by some 150 plugins for pytest.
|
||||
|
||||
Pluggy uses semantic versioning. Breaking changes are only foreseen for
|
||||
Major releases (incremented X in "X.Y.Z"). If you want to use pluggy in
|
||||
your project you should thus use a dependency restriction like
|
||||
"pluggy>=0.1.0,<1.0" to avoid surprises.
|
||||
|
||||
pluggy is concerned with hook specification, hook implementations and hook
|
||||
calling. For any given hook specification a hook call invokes up to N implementations.
|
||||
A hook implementation can influence its position and type of execution:
|
||||
if attributed "tryfirst" or "trylast" it will be tried to execute
|
||||
first or last. However, if attributed "hookwrapper" an implementation
|
||||
can wrap all calls to non-hookwrapper implementations. A hookwrapper
|
||||
can thus execute some code ahead and after the execution of other hooks.
|
||||
|
||||
Hook specification is done by way of a regular python function where
|
||||
both the function name and the names of all its arguments are significant.
|
||||
Each hook implementation function is verified against the original specification
|
||||
function, including the names of all its arguments. To allow for hook specifications
|
||||
to evolve over the livetime of a project, hook implementations can
|
||||
accept less arguments. One can thus add new arguments and semantics to
|
||||
a hook specification by adding another argument typically without breaking
|
||||
existing hook implementations.
|
||||
|
||||
The chosen approach is meant to let a hook designer think carefuly about
|
||||
which objects are needed by an extension writer. By contrast, subclass-based
|
||||
extension mechanisms often expose a lot more state and behaviour than needed,
|
||||
thus restricting future developments.
|
||||
|
||||
Pluggy currently consists of functionality for:
|
||||
|
||||
- a way to register new hook specifications. Without a hook
|
||||
specification no hook calling can be performed.
|
||||
|
||||
- a registry of plugins which contain hook implementation functions. It
|
||||
is possible to register plugins for which a hook specification is not yet
|
||||
known and validate all hooks when the system is in a more referentially
|
||||
consistent state. Setting an "optionalhook" attribution to a hook
|
||||
implementation will avoid PluginValidationError's if a specification
|
||||
is missing. This allows to have optional integration between plugins.
|
||||
|
||||
- a "hook" relay object from which you can launch 1:N calls to
|
||||
registered hook implementation functions
|
||||
|
||||
- a mechanism for ordering hook implementation functions
|
||||
|
||||
- mechanisms for two different type of 1:N calls: "firstresult" for when
|
||||
the call should stop when the first implementation returns a non-None result.
|
||||
And the other (default) way of guaranteeing that all hook implementations
|
||||
will be called and their non-None result collected.
|
||||
|
||||
- mechanisms for "historic" extension points such that all newly
|
||||
registered functions will receive all hook calls that happened
|
||||
before their registration.
|
||||
|
||||
- a mechanism for discovering plugin objects which are based on
|
||||
setuptools based entry points.
|
||||
|
||||
- a simple tracing mechanism, including tracing of plugin calls and
|
||||
their arguments.
|
||||
|
||||
"""
|
||||
import sys
|
||||
import inspect
|
||||
|
||||
__version__ = '0.4.0'
|
||||
|
||||
__all__ = ["PluginManager", "PluginValidationError", "HookCallError",
|
||||
"HookspecMarker", "HookimplMarker"]
|
||||
|
||||
_py3 = sys.version_info > (3, 0)
|
||||
|
||||
|
||||
class HookspecMarker:
|
||||
""" Decorator helper class for marking functions as hook specifications.
|
||||
|
||||
You can instantiate it with a project_name to get a decorator.
|
||||
Calling PluginManager.add_hookspecs later will discover all marked functions
|
||||
if the PluginManager uses the same project_name.
|
||||
"""
|
||||
|
||||
def __init__(self, project_name):
|
||||
self.project_name = project_name
|
||||
|
||||
def __call__(self, function=None, firstresult=False, historic=False):
|
||||
""" if passed a function, directly sets attributes on the function
|
||||
which will make it discoverable to add_hookspecs(). If passed no
|
||||
function, returns a decorator which can be applied to a function
|
||||
later using the attributes supplied.
|
||||
|
||||
If firstresult is True the 1:N hook call (N being the number of registered
|
||||
hook implementation functions) will stop at I<=N when the I'th function
|
||||
returns a non-None result.
|
||||
|
||||
If historic is True calls to a hook will be memorized and replayed
|
||||
on later registered plugins.
|
||||
|
||||
"""
|
||||
def setattr_hookspec_opts(func):
|
||||
if historic and firstresult:
|
||||
raise ValueError("cannot have a historic firstresult hook")
|
||||
setattr(func, self.project_name + "_spec",
|
||||
dict(firstresult=firstresult, historic=historic))
|
||||
return func
|
||||
|
||||
if function is not None:
|
||||
return setattr_hookspec_opts(function)
|
||||
else:
|
||||
return setattr_hookspec_opts
|
||||
|
||||
|
||||
class HookimplMarker:
|
||||
""" Decorator helper class for marking functions as hook implementations.
|
||||
|
||||
You can instantiate with a project_name to get a decorator.
|
||||
Calling PluginManager.register later will discover all marked functions
|
||||
if the PluginManager uses the same project_name.
|
||||
"""
|
||||
def __init__(self, project_name):
|
||||
self.project_name = project_name
|
||||
|
||||
def __call__(self, function=None, hookwrapper=False, optionalhook=False,
|
||||
tryfirst=False, trylast=False):
|
||||
|
||||
""" if passed a function, directly sets attributes on the function
|
||||
which will make it discoverable to register(). If passed no function,
|
||||
returns a decorator which can be applied to a function later using
|
||||
the attributes supplied.
|
||||
|
||||
If optionalhook is True a missing matching hook specification will not result
|
||||
in an error (by default it is an error if no matching spec is found).
|
||||
|
||||
If tryfirst is True this hook implementation will run as early as possible
|
||||
in the chain of N hook implementations for a specfication.
|
||||
|
||||
If trylast is True this hook implementation will run as late as possible
|
||||
in the chain of N hook implementations.
|
||||
|
||||
If hookwrapper is True the hook implementations needs to execute exactly
|
||||
one "yield". The code before the yield is run early before any non-hookwrapper
|
||||
function is run. The code after the yield is run after all non-hookwrapper
|
||||
function have run. The yield receives an ``_CallOutcome`` object representing
|
||||
the exception or result outcome of the inner calls (including other hookwrapper
|
||||
calls).
|
||||
|
||||
"""
|
||||
def setattr_hookimpl_opts(func):
|
||||
setattr(func, self.project_name + "_impl",
|
||||
dict(hookwrapper=hookwrapper, optionalhook=optionalhook,
|
||||
tryfirst=tryfirst, trylast=trylast))
|
||||
return func
|
||||
|
||||
if function is None:
|
||||
return setattr_hookimpl_opts
|
||||
else:
|
||||
return setattr_hookimpl_opts(function)
|
||||
|
||||
|
||||
def normalize_hookimpl_opts(opts):
|
||||
opts.setdefault("tryfirst", False)
|
||||
opts.setdefault("trylast", False)
|
||||
opts.setdefault("hookwrapper", False)
|
||||
opts.setdefault("optionalhook", False)
|
||||
|
||||
|
||||
class _TagTracer:
|
||||
def __init__(self):
|
||||
self._tag2proc = {}
|
||||
self.writer = None
|
||||
self.indent = 0
|
||||
|
||||
def get(self, name):
|
||||
return _TagTracerSub(self, (name,))
|
||||
|
||||
def format_message(self, tags, args):
|
||||
if isinstance(args[-1], dict):
|
||||
extra = args[-1]
|
||||
args = args[:-1]
|
||||
else:
|
||||
extra = {}
|
||||
|
||||
content = " ".join(map(str, args))
|
||||
indent = " " * self.indent
|
||||
|
||||
lines = [
|
||||
"%s%s [%s]\n" % (indent, content, ":".join(tags))
|
||||
]
|
||||
|
||||
for name, value in extra.items():
|
||||
lines.append("%s %s: %s\n" % (indent, name, value))
|
||||
return lines
|
||||
|
||||
def processmessage(self, tags, args):
|
||||
if self.writer is not None and args:
|
||||
lines = self.format_message(tags, args)
|
||||
self.writer(''.join(lines))
|
||||
try:
|
||||
self._tag2proc[tags](tags, args)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def setwriter(self, writer):
|
||||
self.writer = writer
|
||||
|
||||
def setprocessor(self, tags, processor):
|
||||
if isinstance(tags, str):
|
||||
tags = tuple(tags.split(":"))
|
||||
else:
|
||||
assert isinstance(tags, tuple)
|
||||
self._tag2proc[tags] = processor
|
||||
|
||||
|
||||
class _TagTracerSub:
|
||||
def __init__(self, root, tags):
|
||||
self.root = root
|
||||
self.tags = tags
|
||||
|
||||
def __call__(self, *args):
|
||||
self.root.processmessage(self.tags, args)
|
||||
|
||||
def setmyprocessor(self, processor):
|
||||
self.root.setprocessor(self.tags, processor)
|
||||
|
||||
def get(self, name):
|
||||
return self.__class__(self.root, self.tags + (name,))
|
||||
|
||||
|
||||
def _raise_wrapfail(wrap_controller, msg):
|
||||
co = wrap_controller.gi_code
|
||||
raise RuntimeError("wrap_controller at %r %s:%d %s" %
|
||||
(co.co_name, co.co_filename, co.co_firstlineno, msg))
|
||||
|
||||
|
||||
def _wrapped_call(wrap_controller, func):
|
||||
""" Wrap calling to a function with a generator which needs to yield
|
||||
exactly once. The yield point will trigger calling the wrapped function
|
||||
and return its _CallOutcome to the yield point. The generator then needs
|
||||
to finish (raise StopIteration) in order for the wrapped call to complete.
|
||||
"""
|
||||
try:
|
||||
next(wrap_controller) # first yield
|
||||
except StopIteration:
|
||||
_raise_wrapfail(wrap_controller, "did not yield")
|
||||
call_outcome = _CallOutcome(func)
|
||||
try:
|
||||
wrap_controller.send(call_outcome)
|
||||
_raise_wrapfail(wrap_controller, "has second yield")
|
||||
except StopIteration:
|
||||
pass
|
||||
return call_outcome.get_result()
|
||||
|
||||
|
||||
class _CallOutcome:
|
||||
""" Outcome of a function call, either an exception or a proper result.
|
||||
Calling the ``get_result`` method will return the result or reraise
|
||||
the exception raised when the function was called. """
|
||||
excinfo = None
|
||||
|
||||
def __init__(self, func):
|
||||
try:
|
||||
self.result = func()
|
||||
except BaseException:
|
||||
self.excinfo = sys.exc_info()
|
||||
|
||||
def force_result(self, result):
|
||||
self.result = result
|
||||
self.excinfo = None
|
||||
|
||||
def get_result(self):
|
||||
if self.excinfo is None:
|
||||
return self.result
|
||||
else:
|
||||
ex = self.excinfo
|
||||
if _py3:
|
||||
raise ex[1].with_traceback(ex[2])
|
||||
_reraise(*ex) # noqa
|
||||
|
||||
if not _py3:
|
||||
exec("""
|
||||
def _reraise(cls, val, tb):
|
||||
raise cls, val, tb
|
||||
""")
|
||||
|
||||
|
||||
class _TracedHookExecution:
|
||||
def __init__(self, pluginmanager, before, after):
|
||||
self.pluginmanager = pluginmanager
|
||||
self.before = before
|
||||
self.after = after
|
||||
self.oldcall = pluginmanager._inner_hookexec
|
||||
assert not isinstance(self.oldcall, _TracedHookExecution)
|
||||
self.pluginmanager._inner_hookexec = self
|
||||
|
||||
def __call__(self, hook, hook_impls, kwargs):
|
||||
self.before(hook.name, hook_impls, kwargs)
|
||||
outcome = _CallOutcome(lambda: self.oldcall(hook, hook_impls, kwargs))
|
||||
self.after(outcome, hook.name, hook_impls, kwargs)
|
||||
return outcome.get_result()
|
||||
|
||||
def undo(self):
|
||||
self.pluginmanager._inner_hookexec = self.oldcall
|
||||
|
||||
|
||||
class PluginManager(object):
|
||||
""" Core Pluginmanager class which manages registration
|
||||
of plugin objects and 1:N hook calling.
|
||||
|
||||
You can register new hooks by calling ``add_hookspec(module_or_class)``.
|
||||
You can register plugin objects (which contain hooks) by calling
|
||||
``register(plugin)``. The Pluginmanager is initialized with a
|
||||
prefix that is searched for in the names of the dict of registered
|
||||
plugin objects. An optional excludefunc allows to blacklist names which
|
||||
are not considered as hooks despite a matching prefix.
|
||||
|
||||
For debugging purposes you can call ``enable_tracing()``
|
||||
which will subsequently send debug information to the trace helper.
|
||||
"""
|
||||
|
||||
def __init__(self, project_name, implprefix=None):
|
||||
""" if implprefix is given implementation functions
|
||||
will be recognized if their name matches the implprefix. """
|
||||
self.project_name = project_name
|
||||
self._name2plugin = {}
|
||||
self._plugin2hookcallers = {}
|
||||
self._plugin_distinfo = []
|
||||
self.trace = _TagTracer().get("pluginmanage")
|
||||
self.hook = _HookRelay(self.trace.root.get("hook"))
|
||||
self._implprefix = implprefix
|
||||
self._inner_hookexec = lambda hook, methods, kwargs: \
|
||||
_MultiCall(methods, kwargs, hook.spec_opts).execute()
|
||||
|
||||
def _hookexec(self, hook, methods, kwargs):
|
||||
# called from all hookcaller instances.
|
||||
# enable_tracing will set its own wrapping function at self._inner_hookexec
|
||||
return self._inner_hookexec(hook, methods, kwargs)
|
||||
|
||||
def register(self, plugin, name=None):
|
||||
""" Register a plugin and return its canonical name or None if the name
|
||||
is blocked from registering. Raise a ValueError if the plugin is already
|
||||
registered. """
|
||||
plugin_name = name or self.get_canonical_name(plugin)
|
||||
|
||||
if plugin_name in self._name2plugin or plugin in self._plugin2hookcallers:
|
||||
if self._name2plugin.get(plugin_name, -1) is None:
|
||||
return # blocked plugin, return None to indicate no registration
|
||||
raise ValueError("Plugin already registered: %s=%s\n%s" %
|
||||
(plugin_name, plugin, self._name2plugin))
|
||||
|
||||
# XXX if an error happens we should make sure no state has been
|
||||
# changed at point of return
|
||||
self._name2plugin[plugin_name] = plugin
|
||||
|
||||
# register matching hook implementations of the plugin
|
||||
self._plugin2hookcallers[plugin] = hookcallers = []
|
||||
for name in dir(plugin):
|
||||
hookimpl_opts = self.parse_hookimpl_opts(plugin, name)
|
||||
if hookimpl_opts is not None:
|
||||
normalize_hookimpl_opts(hookimpl_opts)
|
||||
method = getattr(plugin, name)
|
||||
hookimpl = HookImpl(plugin, plugin_name, method, hookimpl_opts)
|
||||
hook = getattr(self.hook, name, None)
|
||||
if hook is None:
|
||||
hook = _HookCaller(name, self._hookexec)
|
||||
setattr(self.hook, name, hook)
|
||||
elif hook.has_spec():
|
||||
self._verify_hook(hook, hookimpl)
|
||||
hook._maybe_apply_history(hookimpl)
|
||||
hook._add_hookimpl(hookimpl)
|
||||
hookcallers.append(hook)
|
||||
return plugin_name
|
||||
|
||||
def parse_hookimpl_opts(self, plugin, name):
|
||||
method = getattr(plugin, name)
|
||||
try:
|
||||
res = getattr(method, self.project_name + "_impl", None)
|
||||
except Exception:
|
||||
res = {}
|
||||
if res is not None and not isinstance(res, dict):
|
||||
# false positive
|
||||
res = None
|
||||
elif res is None and self._implprefix and name.startswith(self._implprefix):
|
||||
res = {}
|
||||
return res
|
||||
|
||||
def unregister(self, plugin=None, name=None):
|
||||
""" unregister a plugin object and all its contained hook implementations
|
||||
from internal data structures. """
|
||||
if name is None:
|
||||
assert plugin is not None, "one of name or plugin needs to be specified"
|
||||
name = self.get_name(plugin)
|
||||
|
||||
if plugin is None:
|
||||
plugin = self.get_plugin(name)
|
||||
|
||||
# if self._name2plugin[name] == None registration was blocked: ignore
|
||||
if self._name2plugin.get(name):
|
||||
del self._name2plugin[name]
|
||||
|
||||
for hookcaller in self._plugin2hookcallers.pop(plugin, []):
|
||||
hookcaller._remove_plugin(plugin)
|
||||
|
||||
return plugin
|
||||
|
||||
def set_blocked(self, name):
|
||||
""" block registrations of the given name, unregister if already registered. """
|
||||
self.unregister(name=name)
|
||||
self._name2plugin[name] = None
|
||||
|
||||
def is_blocked(self, name):
|
||||
""" return True if the name blogs registering plugins of that name. """
|
||||
return name in self._name2plugin and self._name2plugin[name] is None
|
||||
|
||||
def add_hookspecs(self, module_or_class):
|
||||
""" add new hook specifications defined in the given module_or_class.
|
||||
Functions are recognized if they have been decorated accordingly. """
|
||||
names = []
|
||||
for name in dir(module_or_class):
|
||||
spec_opts = self.parse_hookspec_opts(module_or_class, name)
|
||||
if spec_opts is not None:
|
||||
hc = getattr(self.hook, name, None)
|
||||
if hc is None:
|
||||
hc = _HookCaller(name, self._hookexec, module_or_class, spec_opts)
|
||||
setattr(self.hook, name, hc)
|
||||
else:
|
||||
# plugins registered this hook without knowing the spec
|
||||
hc.set_specification(module_or_class, spec_opts)
|
||||
for hookfunction in (hc._wrappers + hc._nonwrappers):
|
||||
self._verify_hook(hc, hookfunction)
|
||||
names.append(name)
|
||||
|
||||
if not names:
|
||||
raise ValueError("did not find any %r hooks in %r" %
|
||||
(self.project_name, module_or_class))
|
||||
|
||||
def parse_hookspec_opts(self, module_or_class, name):
|
||||
method = getattr(module_or_class, name)
|
||||
return getattr(method, self.project_name + "_spec", None)
|
||||
|
||||
def get_plugins(self):
|
||||
""" return the set of registered plugins. """
|
||||
return set(self._plugin2hookcallers)
|
||||
|
||||
def is_registered(self, plugin):
|
||||
""" Return True if the plugin is already registered. """
|
||||
return plugin in self._plugin2hookcallers
|
||||
|
||||
def get_canonical_name(self, plugin):
|
||||
""" Return canonical name for a plugin object. Note that a plugin
|
||||
may be registered under a different name which was specified
|
||||
by the caller of register(plugin, name). To obtain the name
|
||||
of an registered plugin use ``get_name(plugin)`` instead."""
|
||||
return getattr(plugin, "__name__", None) or str(id(plugin))
|
||||
|
||||
def get_plugin(self, name):
|
||||
""" Return a plugin or None for the given name. """
|
||||
return self._name2plugin.get(name)
|
||||
|
||||
def has_plugin(self, name):
|
||||
""" Return True if a plugin with the given name is registered. """
|
||||
return self.get_plugin(name) is not None
|
||||
|
||||
def get_name(self, plugin):
|
||||
""" Return name for registered plugin or None if not registered. """
|
||||
for name, val in self._name2plugin.items():
|
||||
if plugin == val:
|
||||
return name
|
||||
|
||||
def _verify_hook(self, hook, hookimpl):
|
||||
if hook.is_historic() and hookimpl.hookwrapper:
|
||||
raise PluginValidationError(
|
||||
"Plugin %r\nhook %r\nhistoric incompatible to hookwrapper" %
|
||||
(hookimpl.plugin_name, hook.name))
|
||||
|
||||
for arg in hookimpl.argnames:
|
||||
if arg not in hook.argnames:
|
||||
raise PluginValidationError(
|
||||
"Plugin %r\nhook %r\nargument %r not available\n"
|
||||
"plugin definition: %s\n"
|
||||
"available hookargs: %s" %
|
||||
(hookimpl.plugin_name, hook.name, arg,
|
||||
_formatdef(hookimpl.function), ", ".join(hook.argnames)))
|
||||
|
||||
def check_pending(self):
|
||||
""" Verify that all hooks which have not been verified against
|
||||
a hook specification are optional, otherwise raise PluginValidationError"""
|
||||
for name in self.hook.__dict__:
|
||||
if name[0] != "_":
|
||||
hook = getattr(self.hook, name)
|
||||
if not hook.has_spec():
|
||||
for hookimpl in (hook._wrappers + hook._nonwrappers):
|
||||
if not hookimpl.optionalhook:
|
||||
raise PluginValidationError(
|
||||
"unknown hook %r in plugin %r" %
|
||||
(name, hookimpl.plugin))
|
||||
|
||||
def load_setuptools_entrypoints(self, entrypoint_name):
|
||||
""" Load modules from querying the specified setuptools entrypoint name.
|
||||
Return the number of loaded plugins. """
|
||||
from pkg_resources import (iter_entry_points, DistributionNotFound,
|
||||
VersionConflict)
|
||||
for ep in iter_entry_points(entrypoint_name):
|
||||
# is the plugin registered or blocked?
|
||||
if self.get_plugin(ep.name) or self.is_blocked(ep.name):
|
||||
continue
|
||||
try:
|
||||
plugin = ep.load()
|
||||
except DistributionNotFound:
|
||||
continue
|
||||
except VersionConflict as e:
|
||||
raise PluginValidationError(
|
||||
"Plugin %r could not be loaded: %s!" % (ep.name, e))
|
||||
self.register(plugin, name=ep.name)
|
||||
self._plugin_distinfo.append((plugin, ep.dist))
|
||||
return len(self._plugin_distinfo)
|
||||
|
||||
def list_plugin_distinfo(self):
|
||||
""" return list of distinfo/plugin tuples for all setuptools registered
|
||||
plugins. """
|
||||
return list(self._plugin_distinfo)
|
||||
|
||||
def list_name_plugin(self):
|
||||
""" return list of name/plugin pairs. """
|
||||
return list(self._name2plugin.items())
|
||||
|
||||
def get_hookcallers(self, plugin):
|
||||
""" get all hook callers for the specified plugin. """
|
||||
return self._plugin2hookcallers.get(plugin)
|
||||
|
||||
def add_hookcall_monitoring(self, before, after):
|
||||
""" add before/after tracing functions for all hooks
|
||||
and return an undo function which, when called,
|
||||
will remove the added tracers.
|
||||
|
||||
``before(hook_name, hook_impls, kwargs)`` will be called ahead
|
||||
of all hook calls and receive a hookcaller instance, a list
|
||||
of HookImpl instances and the keyword arguments for the hook call.
|
||||
|
||||
``after(outcome, hook_name, hook_impls, kwargs)`` receives the
|
||||
same arguments as ``before`` but also a :py:class:`_CallOutcome <_pytest.vendored_packages.pluggy._CallOutcome>` object
|
||||
which represents the result of the overall hook call.
|
||||
"""
|
||||
return _TracedHookExecution(self, before, after).undo
|
||||
|
||||
def enable_tracing(self):
|
||||
""" enable tracing of hook calls and return an undo function. """
|
||||
hooktrace = self.hook._trace
|
||||
|
||||
def before(hook_name, methods, kwargs):
|
||||
hooktrace.root.indent += 1
|
||||
hooktrace(hook_name, kwargs)
|
||||
|
||||
def after(outcome, hook_name, methods, kwargs):
|
||||
if outcome.excinfo is None:
|
||||
hooktrace("finish", hook_name, "-->", outcome.result)
|
||||
hooktrace.root.indent -= 1
|
||||
|
||||
return self.add_hookcall_monitoring(before, after)
|
||||
|
||||
def subset_hook_caller(self, name, remove_plugins):
|
||||
""" Return a new _HookCaller instance for the named method
|
||||
which manages calls to all registered plugins except the
|
||||
ones from remove_plugins. """
|
||||
orig = getattr(self.hook, name)
|
||||
plugins_to_remove = [plug for plug in remove_plugins if hasattr(plug, name)]
|
||||
if plugins_to_remove:
|
||||
hc = _HookCaller(orig.name, orig._hookexec, orig._specmodule_or_class,
|
||||
orig.spec_opts)
|
||||
for hookimpl in (orig._wrappers + orig._nonwrappers):
|
||||
plugin = hookimpl.plugin
|
||||
if plugin not in plugins_to_remove:
|
||||
hc._add_hookimpl(hookimpl)
|
||||
# we also keep track of this hook caller so it
|
||||
# gets properly removed on plugin unregistration
|
||||
self._plugin2hookcallers.setdefault(plugin, []).append(hc)
|
||||
return hc
|
||||
return orig
|
||||
|
||||
|
||||
class _MultiCall:
|
||||
""" execute a call into multiple python functions/methods. """
|
||||
|
||||
# XXX note that the __multicall__ argument is supported only
|
||||
# for pytest compatibility reasons. It was never officially
|
||||
# supported there and is explicitely deprecated since 2.8
|
||||
# so we can remove it soon, allowing to avoid the below recursion
|
||||
# in execute() and simplify/speed up the execute loop.
|
||||
|
||||
def __init__(self, hook_impls, kwargs, specopts={}):
|
||||
self.hook_impls = hook_impls
|
||||
self.kwargs = kwargs
|
||||
self.kwargs["__multicall__"] = self
|
||||
self.specopts = specopts
|
||||
|
||||
def execute(self):
|
||||
all_kwargs = self.kwargs
|
||||
self.results = results = []
|
||||
firstresult = self.specopts.get("firstresult")
|
||||
|
||||
while self.hook_impls:
|
||||
hook_impl = self.hook_impls.pop()
|
||||
try:
|
||||
args = [all_kwargs[argname] for argname in hook_impl.argnames]
|
||||
except KeyError:
|
||||
for argname in hook_impl.argnames:
|
||||
if argname not in all_kwargs:
|
||||
raise HookCallError(
|
||||
"hook call must provide argument %r" % (argname,))
|
||||
if hook_impl.hookwrapper:
|
||||
return _wrapped_call(hook_impl.function(*args), self.execute)
|
||||
res = hook_impl.function(*args)
|
||||
if res is not None:
|
||||
if firstresult:
|
||||
return res
|
||||
results.append(res)
|
||||
|
||||
if not firstresult:
|
||||
return results
|
||||
|
||||
def __repr__(self):
|
||||
status = "%d meths" % (len(self.hook_impls),)
|
||||
if hasattr(self, "results"):
|
||||
status = ("%d results, " % len(self.results)) + status
|
||||
return "<_MultiCall %s, kwargs=%r>" % (status, self.kwargs)
|
||||
|
||||
|
||||
def varnames(func, startindex=None):
|
||||
""" return argument name tuple for a function, method, class or callable.
|
||||
|
||||
In case of a class, its "__init__" method is considered.
|
||||
For methods the "self" parameter is not included unless you are passing
|
||||
an unbound method with Python3 (which has no supports for unbound methods)
|
||||
"""
|
||||
cache = getattr(func, "__dict__", {})
|
||||
try:
|
||||
return cache["_varnames"]
|
||||
except KeyError:
|
||||
pass
|
||||
if inspect.isclass(func):
|
||||
try:
|
||||
func = func.__init__
|
||||
except AttributeError:
|
||||
return ()
|
||||
startindex = 1
|
||||
else:
|
||||
if not inspect.isfunction(func) and not inspect.ismethod(func):
|
||||
try:
|
||||
func = getattr(func, '__call__', func)
|
||||
except Exception:
|
||||
return ()
|
||||
if startindex is None:
|
||||
startindex = int(inspect.ismethod(func))
|
||||
|
||||
try:
|
||||
rawcode = func.__code__
|
||||
except AttributeError:
|
||||
return ()
|
||||
try:
|
||||
x = rawcode.co_varnames[startindex:rawcode.co_argcount]
|
||||
except AttributeError:
|
||||
x = ()
|
||||
else:
|
||||
defaults = func.__defaults__
|
||||
if defaults:
|
||||
x = x[:-len(defaults)]
|
||||
try:
|
||||
cache["_varnames"] = x
|
||||
except TypeError:
|
||||
pass
|
||||
return x
|
||||
|
||||
|
||||
class _HookRelay:
|
||||
""" hook holder object for performing 1:N hook calls where N is the number
|
||||
of registered plugins.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, trace):
|
||||
self._trace = trace
|
||||
|
||||
|
||||
class _HookCaller(object):
|
||||
def __init__(self, name, hook_execute, specmodule_or_class=None, spec_opts=None):
|
||||
self.name = name
|
||||
self._wrappers = []
|
||||
self._nonwrappers = []
|
||||
self._hookexec = hook_execute
|
||||
if specmodule_or_class is not None:
|
||||
assert spec_opts is not None
|
||||
self.set_specification(specmodule_or_class, spec_opts)
|
||||
|
||||
def has_spec(self):
|
||||
return hasattr(self, "_specmodule_or_class")
|
||||
|
||||
def set_specification(self, specmodule_or_class, spec_opts):
|
||||
assert not self.has_spec()
|
||||
self._specmodule_or_class = specmodule_or_class
|
||||
specfunc = getattr(specmodule_or_class, self.name)
|
||||
argnames = varnames(specfunc, startindex=inspect.isclass(specmodule_or_class))
|
||||
assert "self" not in argnames # sanity check
|
||||
self.argnames = ["__multicall__"] + list(argnames)
|
||||
self.spec_opts = spec_opts
|
||||
if spec_opts.get("historic"):
|
||||
self._call_history = []
|
||||
|
||||
def is_historic(self):
|
||||
return hasattr(self, "_call_history")
|
||||
|
||||
def _remove_plugin(self, plugin):
|
||||
def remove(wrappers):
|
||||
for i, method in enumerate(wrappers):
|
||||
if method.plugin == plugin:
|
||||
del wrappers[i]
|
||||
return True
|
||||
if remove(self._wrappers) is None:
|
||||
if remove(self._nonwrappers) is None:
|
||||
raise ValueError("plugin %r not found" % (plugin,))
|
||||
|
||||
def _add_hookimpl(self, hookimpl):
|
||||
if hookimpl.hookwrapper:
|
||||
methods = self._wrappers
|
||||
else:
|
||||
methods = self._nonwrappers
|
||||
|
||||
if hookimpl.trylast:
|
||||
methods.insert(0, hookimpl)
|
||||
elif hookimpl.tryfirst:
|
||||
methods.append(hookimpl)
|
||||
else:
|
||||
# find last non-tryfirst method
|
||||
i = len(methods) - 1
|
||||
while i >= 0 and methods[i].tryfirst:
|
||||
i -= 1
|
||||
methods.insert(i + 1, hookimpl)
|
||||
|
||||
def __repr__(self):
|
||||
return "<_HookCaller %r>" % (self.name,)
|
||||
|
||||
def __call__(self, **kwargs):
|
||||
assert not self.is_historic()
|
||||
return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
|
||||
|
||||
def call_historic(self, proc=None, kwargs=None):
|
||||
self._call_history.append((kwargs or {}, proc))
|
||||
# historizing hooks don't return results
|
||||
self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
|
||||
|
||||
def call_extra(self, methods, kwargs):
|
||||
""" Call the hook with some additional temporarily participating
|
||||
methods using the specified kwargs as call parameters. """
|
||||
old = list(self._nonwrappers), list(self._wrappers)
|
||||
for method in methods:
|
||||
opts = dict(hookwrapper=False, trylast=False, tryfirst=False)
|
||||
hookimpl = HookImpl(None, "<temp>", method, opts)
|
||||
self._add_hookimpl(hookimpl)
|
||||
try:
|
||||
return self(**kwargs)
|
||||
finally:
|
||||
self._nonwrappers, self._wrappers = old
|
||||
|
||||
def _maybe_apply_history(self, method):
|
||||
if self.is_historic():
|
||||
for kwargs, proc in self._call_history:
|
||||
res = self._hookexec(self, [method], kwargs)
|
||||
if res and proc is not None:
|
||||
proc(res[0])
|
||||
|
||||
|
||||
class HookImpl:
|
||||
def __init__(self, plugin, plugin_name, function, hook_impl_opts):
|
||||
self.function = function
|
||||
self.argnames = varnames(self.function)
|
||||
self.plugin = plugin
|
||||
self.opts = hook_impl_opts
|
||||
self.plugin_name = plugin_name
|
||||
self.__dict__.update(hook_impl_opts)
|
||||
|
||||
|
||||
class PluginValidationError(Exception):
|
||||
""" plugin failed validation. """
|
||||
|
||||
|
||||
class HookCallError(Exception):
|
||||
""" Hook was called wrongly. """
|
||||
|
||||
|
||||
if hasattr(inspect, 'signature'):
|
||||
def _formatdef(func):
|
||||
return "%s%s" % (
|
||||
func.__name__,
|
||||
str(inspect.signature(func))
|
||||
)
|
||||
else:
|
||||
def _formatdef(func):
|
||||
return "%s%s" % (
|
||||
func.__name__,
|
||||
inspect.formatargspec(*inspect.getargspec(func))
|
||||
)
|
||||
@@ -10,9 +10,7 @@ environment:
|
||||
- TOXENV: "coveralls"
|
||||
# note: please use "tox --listenvs" to populate the build matrix below
|
||||
- TOXENV: "linting"
|
||||
- TOXENV: "py26"
|
||||
- TOXENV: "py27"
|
||||
- TOXENV: "py33"
|
||||
- TOXENV: "py34"
|
||||
- TOXENV: "py35"
|
||||
- TOXENV: "py36"
|
||||
@@ -21,10 +19,12 @@ environment:
|
||||
- TOXENV: "py27-xdist"
|
||||
- TOXENV: "py27-trial"
|
||||
- TOXENV: "py27-numpy"
|
||||
- TOXENV: "py27-pluggymaster"
|
||||
- TOXENV: "py36-pexpect"
|
||||
- TOXENV: "py36-xdist"
|
||||
- TOXENV: "py36-trial"
|
||||
- TOXENV: "py36-numpy"
|
||||
- TOXENV: "py36-pluggymaster"
|
||||
- TOXENV: "py27-nobyte"
|
||||
- TOXENV: "doctesting"
|
||||
- TOXENV: "py35-freeze"
|
||||
@@ -42,3 +42,7 @@ build: false # Not a C# project, build stuff at the test step instead.
|
||||
|
||||
test_script:
|
||||
- call scripts\call-tox.bat
|
||||
|
||||
cache:
|
||||
- '%LOCALAPPDATA%\pip\cache'
|
||||
- '%USERPROFILE%\.cache\pre-commit'
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import sys
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
import cProfile
|
||||
import pytest
|
||||
import pytest # NOQA
|
||||
import pstats
|
||||
|
||||
script = sys.argv[1:] if len(sys.argv) > 1 else "empty.py"
|
||||
stats = cProfile.run('pytest.cmdline.main(%r)' % script, 'prof')
|
||||
stats = cProfile.run("pytest.cmdline.main(%r)" % script, "prof")
|
||||
p = pstats.Stats("prof")
|
||||
p.strip_dirs()
|
||||
p.sort_stats('cumulative')
|
||||
p.sort_stats("cumulative")
|
||||
print(p.print_stats(500))
|
||||
|
||||
@@ -5,15 +5,18 @@
|
||||
# FilesCompleter 75.1109 69.2116
|
||||
# FastFilesCompleter 0.7383 1.0760
|
||||
|
||||
import timeit
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
import timeit
|
||||
from argcomplete.completers import FilesCompleter
|
||||
from _pytest._argcomplete import FastFilesCompleter
|
||||
count = 1000 # only a few seconds
|
||||
setup = 'from __main__ import FastFilesCompleter\nfc = FastFilesCompleter()'
|
||||
run = 'fc("/d")'
|
||||
sys.stdout.write('%s\n' % (timeit.timeit(run,
|
||||
setup=setup.replace('Fast', ''), number=count)))
|
||||
sys.stdout.write('%s\n' % (timeit.timeit(run, setup=setup, number=count)))
|
||||
imports = [
|
||||
"from argcomplete.completers import FilesCompleter as completer",
|
||||
"from _pytest._argcomplete import FastFilesCompleter as completer",
|
||||
]
|
||||
|
||||
count = 1000 # only a few seconds
|
||||
setup = "%s\nfc = completer()"
|
||||
run = 'fc("/d")'
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(timeit.timeit(run, setup=setup % imports[0], number=count))
|
||||
print((timeit.timeit(run, setup=setup % imports[1], number=count)))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import py
|
||||
|
||||
for i in range(1000):
|
||||
py.builtin.exec_("def test_func_%d(): pass" % i)
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
|
||||
import pytest
|
||||
|
||||
@pytest.fixture(scope='module', params=range(966))
|
||||
|
||||
@pytest.fixture(scope="module", params=range(966))
|
||||
def foo(request):
|
||||
return request.param
|
||||
|
||||
|
||||
def test_it(foo):
|
||||
pass
|
||||
|
||||
|
||||
def test_it2(foo):
|
||||
pass
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
|
||||
from six.moves import range
|
||||
import pytest
|
||||
|
||||
|
||||
SKIP = True
|
||||
|
||||
@pytest.mark.parametrize("x", xrange(5000))
|
||||
|
||||
@pytest.mark.parametrize("x", range(5000))
|
||||
def test_foo(x):
|
||||
if SKIP:
|
||||
pytest.skip("heh")
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Match fixture paths against actual path segments in order to avoid matching folders which share a prefix.
|
||||
32
changelog/README.rst
Normal file
32
changelog/README.rst
Normal file
@@ -0,0 +1,32 @@
|
||||
This directory contains "newsfragments" which are short files that contain a small **ReST**-formatted
|
||||
text that will be added to the next ``CHANGELOG``.
|
||||
|
||||
The ``CHANGELOG`` will be read by users, so this description should be aimed to pytest users
|
||||
instead of describing internal changes which are only relevant to the developers.
|
||||
|
||||
Make sure to use full sentences with correct case and punctuation, for example::
|
||||
|
||||
Fix issue with non-ascii messages from the ``warnings`` module.
|
||||
|
||||
Each file should be named like ``<ISSUE>.<TYPE>.rst``, where
|
||||
``<ISSUE>`` is an issue number, and ``<TYPE>`` is one of:
|
||||
|
||||
* ``feature``: new user facing features, like new command-line options and new behavior.
|
||||
* ``bugfix``: fixes a reported bug.
|
||||
* ``doc``: documentation improvement, like rewording an entire session or adding missing docs.
|
||||
* ``removal``: feature deprecation or removal.
|
||||
* ``vendor``: changes in packages vendored in pytest.
|
||||
* ``trivial``: fixing a small typo or internal change that might be noteworthy.
|
||||
|
||||
So for example: ``123.feature.rst``, ``456.bugfix.rst``.
|
||||
|
||||
If your PR fixes an issue, use that number here. If there is no issue,
|
||||
then after you submit the PR and get the PR number you can add a
|
||||
changelog using that instead.
|
||||
|
||||
If you are not sure what issue type to use, don't hesitate to ask in your PR.
|
||||
|
||||
Note that the ``towncrier`` tool will automatically
|
||||
reflow your text, so it will work best if you stick to a single paragraph, but multiple sentences and links are OK
|
||||
and encouraged. You can install ``towncrier`` and then run ``towncrier --draft``
|
||||
if you want to get a preview of how your change will look in the final release notes.
|
||||
@@ -13,8 +13,6 @@ PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
REGENDOC_ARGS := \
|
||||
--normalize "/={8,} (.*) ={8,}/======= \1 ========/" \
|
||||
--normalize "/_{8,} (.*) _{8,}/_______ \1 ________/" \
|
||||
--normalize "/in \d+.\d+ seconds/in 0.12 seconds/" \
|
||||
--normalize "@/tmp/pytest-of-.*/pytest-\d+@PYTEST_TMPDIR@" \
|
||||
--normalize "@pytest-(\d+)\\.[^ ,]+@pytest-\1.x.y@" \
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
|
||||
<ul>
|
||||
<li><a href="{{ pathto('index') }}">Home</a></li>
|
||||
<li><a href="{{ pathto('contents') }}">Contents</a></li>
|
||||
<li><a href="{{ pathto('getting-started') }}">Install</a></li>
|
||||
<li><a href="{{ pathto('contents') }}">Contents</a></li>
|
||||
<li><a href="{{ pathto('reference') }}">Reference</a></li>
|
||||
<li><a href="{{ pathto('example/index') }}">Examples</a></li>
|
||||
<li><a href="{{ pathto('customize') }}">Customize</a></li>
|
||||
<li><a href="{{ pathto('contact') }}">Contact</a></li>
|
||||
<li><a href="{{ pathto('talks') }}">Talks/Posts</a></li>
|
||||
<li><a href="{{ pathto('changelog') }}">Changelog</a></li>
|
||||
<li><a href="{{ pathto('contributing') }}">Contributing</a></li>
|
||||
<li><a href="{{ pathto('backwards-compatibility') }}">Backwards Compatibility</a></li>
|
||||
<li><a href="{{ pathto('license') }}">License</a></li>
|
||||
<li><a href="{{ pathto('contact') }}">Contact Channels</a></li>
|
||||
</ul>
|
||||
|
||||
{%- if display_toc %}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
<h3>Useful Links</h3>
|
||||
<ul>
|
||||
<li><a href="{{ pathto('index') }}">The pytest Website</a></li>
|
||||
<li><a href="{{ pathto('contributing') }}">Contribution Guide</a></li>
|
||||
<li><a href="https://pypi.python.org/pypi/pytest">pytest @ PyPI</a></li>
|
||||
<li><a href="https://pypi.org/project/pytest/">pytest @ PyPI</a></li>
|
||||
<li><a href="https://github.com/pytest-dev/pytest/">pytest @ GitHub</a></li>
|
||||
<li><a href="http://plugincompat.herokuapp.com/">3rd party plugins</a></li>
|
||||
<li><a href="https://github.com/pytest-dev/pytest/issues">Issue Tracker</a></li>
|
||||
<li><a href="https://media.readthedocs.org/pdf/pytest/latest/pytest.pdf">PDF Documentation</a>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -6,4 +6,4 @@ pygments_style = flask_theme_support.FlaskyStyle
|
||||
[options]
|
||||
index_logo = ''
|
||||
index_logo_height = 120px
|
||||
touch_icon =
|
||||
touch_icon =
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
# flasky extensions. flasky pygments style based on tango style
|
||||
from pygments.style import Style
|
||||
from pygments.token import Keyword, Name, Comment, String, Error, \
|
||||
Number, Operator, Generic, Whitespace, Punctuation, Other, Literal
|
||||
from pygments.token import (
|
||||
Keyword,
|
||||
Name,
|
||||
Comment,
|
||||
String,
|
||||
Error,
|
||||
Number,
|
||||
Operator,
|
||||
Generic,
|
||||
Whitespace,
|
||||
Punctuation,
|
||||
Other,
|
||||
Literal,
|
||||
)
|
||||
|
||||
|
||||
class FlaskyStyle(Style):
|
||||
@@ -10,77 +22,68 @@ class FlaskyStyle(Style):
|
||||
|
||||
styles = {
|
||||
# No corresponding class for the following:
|
||||
#Text: "", # class: ''
|
||||
Whitespace: "underline #f8f8f8", # class: 'w'
|
||||
Error: "#a40000 border:#ef2929", # class: 'err'
|
||||
Other: "#000000", # class 'x'
|
||||
|
||||
Comment: "italic #8f5902", # class: 'c'
|
||||
Comment.Preproc: "noitalic", # class: 'cp'
|
||||
|
||||
Keyword: "bold #004461", # class: 'k'
|
||||
Keyword.Constant: "bold #004461", # class: 'kc'
|
||||
Keyword.Declaration: "bold #004461", # class: 'kd'
|
||||
Keyword.Namespace: "bold #004461", # class: 'kn'
|
||||
Keyword.Pseudo: "bold #004461", # class: 'kp'
|
||||
Keyword.Reserved: "bold #004461", # class: 'kr'
|
||||
Keyword.Type: "bold #004461", # class: 'kt'
|
||||
|
||||
Operator: "#582800", # class: 'o'
|
||||
Operator.Word: "bold #004461", # class: 'ow' - like keywords
|
||||
|
||||
Punctuation: "bold #000000", # class: 'p'
|
||||
|
||||
# Text: "", # class: ''
|
||||
Whitespace: "underline #f8f8f8", # class: 'w'
|
||||
Error: "#a40000 border:#ef2929", # class: 'err'
|
||||
Other: "#000000", # class 'x'
|
||||
Comment: "italic #8f5902", # class: 'c'
|
||||
Comment.Preproc: "noitalic", # class: 'cp'
|
||||
Keyword: "bold #004461", # class: 'k'
|
||||
Keyword.Constant: "bold #004461", # class: 'kc'
|
||||
Keyword.Declaration: "bold #004461", # class: 'kd'
|
||||
Keyword.Namespace: "bold #004461", # class: 'kn'
|
||||
Keyword.Pseudo: "bold #004461", # class: 'kp'
|
||||
Keyword.Reserved: "bold #004461", # class: 'kr'
|
||||
Keyword.Type: "bold #004461", # class: 'kt'
|
||||
Operator: "#582800", # class: 'o'
|
||||
Operator.Word: "bold #004461", # class: 'ow' - like keywords
|
||||
Punctuation: "bold #000000", # class: 'p'
|
||||
# because special names such as Name.Class, Name.Function, etc.
|
||||
# are not recognized as such later in the parsing, we choose them
|
||||
# to look the same as ordinary variables.
|
||||
Name: "#000000", # class: 'n'
|
||||
Name.Attribute: "#c4a000", # class: 'na' - to be revised
|
||||
Name.Builtin: "#004461", # class: 'nb'
|
||||
Name.Builtin.Pseudo: "#3465a4", # class: 'bp'
|
||||
Name.Class: "#000000", # class: 'nc' - to be revised
|
||||
Name.Constant: "#000000", # class: 'no' - to be revised
|
||||
Name.Decorator: "#888", # class: 'nd' - to be revised
|
||||
Name.Entity: "#ce5c00", # class: 'ni'
|
||||
Name.Exception: "bold #cc0000", # class: 'ne'
|
||||
Name.Function: "#000000", # class: 'nf'
|
||||
Name.Property: "#000000", # class: 'py'
|
||||
Name.Label: "#f57900", # class: 'nl'
|
||||
Name.Namespace: "#000000", # class: 'nn' - to be revised
|
||||
Name.Other: "#000000", # class: 'nx'
|
||||
Name.Tag: "bold #004461", # class: 'nt' - like a keyword
|
||||
Name.Variable: "#000000", # class: 'nv' - to be revised
|
||||
Name.Variable.Class: "#000000", # class: 'vc' - to be revised
|
||||
Name.Variable.Global: "#000000", # class: 'vg' - to be revised
|
||||
Name.Variable.Instance: "#000000", # class: 'vi' - to be revised
|
||||
|
||||
Number: "#990000", # class: 'm'
|
||||
|
||||
Literal: "#000000", # class: 'l'
|
||||
Literal.Date: "#000000", # class: 'ld'
|
||||
|
||||
String: "#4e9a06", # class: 's'
|
||||
String.Backtick: "#4e9a06", # class: 'sb'
|
||||
String.Char: "#4e9a06", # class: 'sc'
|
||||
String.Doc: "italic #8f5902", # class: 'sd' - like a comment
|
||||
String.Double: "#4e9a06", # class: 's2'
|
||||
String.Escape: "#4e9a06", # class: 'se'
|
||||
String.Heredoc: "#4e9a06", # class: 'sh'
|
||||
String.Interpol: "#4e9a06", # class: 'si'
|
||||
String.Other: "#4e9a06", # class: 'sx'
|
||||
String.Regex: "#4e9a06", # class: 'sr'
|
||||
String.Single: "#4e9a06", # class: 's1'
|
||||
String.Symbol: "#4e9a06", # class: 'ss'
|
||||
|
||||
Generic: "#000000", # class: 'g'
|
||||
Generic.Deleted: "#a40000", # class: 'gd'
|
||||
Generic.Emph: "italic #000000", # class: 'ge'
|
||||
Generic.Error: "#ef2929", # class: 'gr'
|
||||
Generic.Heading: "bold #000080", # class: 'gh'
|
||||
Generic.Inserted: "#00A000", # class: 'gi'
|
||||
Generic.Output: "#888", # class: 'go'
|
||||
Generic.Prompt: "#745334", # class: 'gp'
|
||||
Generic.Strong: "bold #000000", # class: 'gs'
|
||||
Generic.Subheading: "bold #800080", # class: 'gu'
|
||||
Generic.Traceback: "bold #a40000", # class: 'gt'
|
||||
Name: "#000000", # class: 'n'
|
||||
Name.Attribute: "#c4a000", # class: 'na' - to be revised
|
||||
Name.Builtin: "#004461", # class: 'nb'
|
||||
Name.Builtin.Pseudo: "#3465a4", # class: 'bp'
|
||||
Name.Class: "#000000", # class: 'nc' - to be revised
|
||||
Name.Constant: "#000000", # class: 'no' - to be revised
|
||||
Name.Decorator: "#888", # class: 'nd' - to be revised
|
||||
Name.Entity: "#ce5c00", # class: 'ni'
|
||||
Name.Exception: "bold #cc0000", # class: 'ne'
|
||||
Name.Function: "#000000", # class: 'nf'
|
||||
Name.Property: "#000000", # class: 'py'
|
||||
Name.Label: "#f57900", # class: 'nl'
|
||||
Name.Namespace: "#000000", # class: 'nn' - to be revised
|
||||
Name.Other: "#000000", # class: 'nx'
|
||||
Name.Tag: "bold #004461", # class: 'nt' - like a keyword
|
||||
Name.Variable: "#000000", # class: 'nv' - to be revised
|
||||
Name.Variable.Class: "#000000", # class: 'vc' - to be revised
|
||||
Name.Variable.Global: "#000000", # class: 'vg' - to be revised
|
||||
Name.Variable.Instance: "#000000", # class: 'vi' - to be revised
|
||||
Number: "#990000", # class: 'm'
|
||||
Literal: "#000000", # class: 'l'
|
||||
Literal.Date: "#000000", # class: 'ld'
|
||||
String: "#4e9a06", # class: 's'
|
||||
String.Backtick: "#4e9a06", # class: 'sb'
|
||||
String.Char: "#4e9a06", # class: 'sc'
|
||||
String.Doc: "italic #8f5902", # class: 'sd' - like a comment
|
||||
String.Double: "#4e9a06", # class: 's2'
|
||||
String.Escape: "#4e9a06", # class: 'se'
|
||||
String.Heredoc: "#4e9a06", # class: 'sh'
|
||||
String.Interpol: "#4e9a06", # class: 'si'
|
||||
String.Other: "#4e9a06", # class: 'sx'
|
||||
String.Regex: "#4e9a06", # class: 'sr'
|
||||
String.Single: "#4e9a06", # class: 's1'
|
||||
String.Symbol: "#4e9a06", # class: 'ss'
|
||||
Generic: "#000000", # class: 'g'
|
||||
Generic.Deleted: "#a40000", # class: 'gd'
|
||||
Generic.Emph: "italic #000000", # class: 'ge'
|
||||
Generic.Error: "#ef2929", # class: 'gr'
|
||||
Generic.Heading: "bold #000080", # class: 'gh'
|
||||
Generic.Inserted: "#00A000", # class: 'gi'
|
||||
Generic.Output: "#888", # class: 'go'
|
||||
Generic.Prompt: "#745334", # class: 'gp'
|
||||
Generic.Strong: "bold #000000", # class: 'gs'
|
||||
Generic.Subheading: "bold #800080", # class: 'gu'
|
||||
Generic.Traceback: "bold #a40000", # class: 'gt'
|
||||
}
|
||||
|
||||
@@ -5,7 +5,18 @@ Release announcements
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
|
||||
|
||||
release-3.6.1
|
||||
release-3.6.0
|
||||
release-3.5.1
|
||||
release-3.5.0
|
||||
release-3.4.2
|
||||
release-3.4.1
|
||||
release-3.4.0
|
||||
release-3.3.2
|
||||
release-3.3.1
|
||||
release-3.3.0
|
||||
release-3.2.5
|
||||
release-3.2.4
|
||||
release-3.2.3
|
||||
release-3.2.2
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
py.test 2.0.3: bug fixes and speed ups
|
||||
py.test 2.0.3: bug fixes and speed ups
|
||||
===========================================================================
|
||||
|
||||
Welcome to pytest-2.0.3, a maintenance and bug fix release of pytest,
|
||||
@@ -37,4 +37,3 @@ Changes between 2.0.2 and 2.0.3
|
||||
internally)
|
||||
|
||||
- fix issue37: avoid invalid characters in junitxml's output
|
||||
|
||||
|
||||
@@ -34,4 +34,3 @@ Changes between 2.1.0 and 2.1.1
|
||||
- fix issue59: provide system-out/err tags for junitxml output
|
||||
- fix issue61: assertion rewriting on boolean operations with 3 or more operands
|
||||
- you can now build a man page with "cd doc ; make man"
|
||||
|
||||
|
||||
@@ -30,4 +30,3 @@ Changes between 2.1.1 and 2.1.2
|
||||
- fix issue68 / packages now work with assertion rewriting
|
||||
- fix issue66: use different assertion rewriting caches when the -O option is passed
|
||||
- don't try assertion rewriting on Jython, use reinterp
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ and integration testing. See extensive docs with examples here:
|
||||
|
||||
The release contains another fix to the perfected assertions introduced
|
||||
with the 2.1 series as well as the new possibility to customize reporting
|
||||
for assertion expressions on a per-directory level.
|
||||
for assertion expressions on a per-directory level.
|
||||
|
||||
If you want to install or upgrade pytest, just type one of::
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ Changes between 2.2.0 and 2.2.1
|
||||
----------------------------------------
|
||||
|
||||
- fix issue99 (in pytest and py) internallerrors with resultlog now
|
||||
produce better output - fixed by normalizing pytest_internalerror
|
||||
produce better output - fixed by normalizing pytest_internalerror
|
||||
input arguments.
|
||||
- fix issue97 / traceback issues (in pytest and py) improve traceback output
|
||||
in conjunction with jinja2 and cython which hack tracebacks
|
||||
@@ -35,7 +35,7 @@ Changes between 2.2.0 and 2.2.1
|
||||
the final test in a test node will now run its teardown directly
|
||||
instead of waiting for the end of the session. Thanks Dave Hunt for
|
||||
the good reporting and feedback. The pytest_runtest_protocol as well
|
||||
as the pytest_runtest_teardown hooks now have "nextitem" available
|
||||
as the pytest_runtest_teardown hooks now have "nextitem" available
|
||||
which will be None indicating the end of the test run.
|
||||
- fix collection crash due to unknown-source collected items, thanks
|
||||
to Ralf Schmitt (fixed by depending on a more recent pylib)
|
||||
|
||||
@@ -4,7 +4,7 @@ pytest-2.2.2: bug fixes
|
||||
pytest-2.2.2 (updated to 2.2.3 to fix packaging issues) is a minor
|
||||
backward-compatible release of the versatile py.test testing tool. It
|
||||
contains bug fixes and a few refinements particularly to reporting with
|
||||
"--collectonly", see below for betails.
|
||||
"--collectonly", see below for betails.
|
||||
|
||||
For general information see here:
|
||||
|
||||
@@ -27,7 +27,7 @@ Changes between 2.2.1 and 2.2.2
|
||||
|
||||
- fix issue101: wrong args to unittest.TestCase test function now
|
||||
produce better output
|
||||
- fix issue102: report more useful errors and hints for when a
|
||||
- fix issue102: report more useful errors and hints for when a
|
||||
test directory was renamed and some pyc/__pycache__ remain
|
||||
- fix issue106: allow parametrize to be applied multiple times
|
||||
e.g. from module, class and at function level.
|
||||
@@ -38,6 +38,6 @@ Changes between 2.2.1 and 2.2.2
|
||||
- fix issue115: make --collectonly robust against early failure
|
||||
(missing files/directories)
|
||||
- "-qq --collectonly" now shows only files and the number of tests in them
|
||||
- "-q --collectonly" now shows test ids
|
||||
- "-q --collectonly" now shows test ids
|
||||
- allow adding of attributes to test reports such that it also works
|
||||
with distributed testing (no upgrade of pytest-xdist needed)
|
||||
|
||||
@@ -36,4 +36,3 @@ Changes between 2.2.3 and 2.2.4
|
||||
configure/sessionstart where called
|
||||
- fix issue #144: better mangle test ids to junitxml classnames
|
||||
- upgrade distribute_setup.py to 0.6.27
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.3: improved fixtures / better unittest integration
|
||||
=============================================================================
|
||||
|
||||
pytest-2.3 comes with many major improvements for fixture/funcarg management
|
||||
pytest-2.3 comes with many major improvements for fixture/funcarg management
|
||||
and parametrized testing in Python. It is now easier, more efficient and
|
||||
more predicatable to re-run the same tests with different fixture
|
||||
instances. Also, you can directly declare the caching "scope" of
|
||||
@@ -9,7 +9,7 @@ fixtures so that dependent tests throughout your whole test suite can
|
||||
re-use database or other expensive fixture objects with ease. Lastly,
|
||||
it's possible for fixture functions (formerly known as funcarg
|
||||
factories) to use other fixtures, allowing for a completely modular and
|
||||
re-useable fixture design.
|
||||
re-useable fixture design.
|
||||
|
||||
For detailed info and tutorial-style examples, see:
|
||||
|
||||
@@ -27,7 +27,7 @@ All changes are backward compatible and you should be able to continue
|
||||
to run your test suites and 3rd party plugins that worked with
|
||||
pytest-2.2.4.
|
||||
|
||||
If you are interested in the precise reasoning (including examples) of the
|
||||
If you are interested in the precise reasoning (including examples) of the
|
||||
pytest-2.3 fixture evolution, please consult
|
||||
http://pytest.org/latest/funcarg_compare.html
|
||||
|
||||
@@ -43,7 +43,7 @@ and more details for those already in the knowing of pytest can be found
|
||||
in the CHANGELOG below.
|
||||
|
||||
Particular thanks for this release go to Floris Bruynooghe, Alex Okrushko
|
||||
Carl Meyer, Ronny Pfannschmidt, Benjamin Peterson and Alex Gaynor for helping
|
||||
Carl Meyer, Ronny Pfannschmidt, Benjamin Peterson and Alex Gaynor for helping
|
||||
to get the new features right and well integrated. Ronny and Floris
|
||||
also helped to fix a number of bugs and yet more people helped by
|
||||
providing bug reports.
|
||||
@@ -94,7 +94,7 @@ Changes between 2.2.4 and 2.3.0
|
||||
- pluginmanager.register(...) now raises ValueError if the
|
||||
plugin has been already registered or the name is taken
|
||||
|
||||
- fix issue159: improve http://pytest.org/latest/faq.html
|
||||
- fix issue159: improve http://pytest.org/latest/faq.html
|
||||
especially with respect to the "magic" history, also mention
|
||||
pytest-django, trial and unittest integration.
|
||||
|
||||
@@ -125,10 +125,9 @@ Changes between 2.2.4 and 2.3.0
|
||||
you can use startdir.bestrelpath(yourpath) to show
|
||||
nice relative path
|
||||
|
||||
- allow plugins to implement both pytest_report_header and
|
||||
- allow plugins to implement both pytest_report_header and
|
||||
pytest_sessionstart (sessionstart is invoked first).
|
||||
|
||||
- don't show deselected reason line if there is none
|
||||
|
||||
- py.test -vv will show all of assert comparisons instead of truncating
|
||||
|
||||
|
||||
@@ -3,16 +3,16 @@ pytest-2.3.1: fix regression with factory functions
|
||||
|
||||
pytest-2.3.1 is a quick follow-up release:
|
||||
|
||||
- fix issue202 - regression with fixture functions/funcarg factories:
|
||||
using "self" is now safe again and works as in 2.2.4. Thanks
|
||||
- fix issue202 - regression with fixture functions/funcarg factories:
|
||||
using "self" is now safe again and works as in 2.2.4. Thanks
|
||||
to Eduard Schettino for the quick bug report.
|
||||
|
||||
- disable pexpect pytest self tests on Freebsd - thanks Koob for the
|
||||
- disable pexpect pytest self tests on Freebsd - thanks Koob for the
|
||||
quick reporting
|
||||
|
||||
- fix/improve interactive docs with --markers
|
||||
|
||||
See
|
||||
See
|
||||
|
||||
http://pytest.org/
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@ pytest-2.3.2 is another stabilization release:
|
||||
- fix teardown-ordering for parametrized setups
|
||||
- fix unittest and trial compat behaviour with respect to runTest() methods
|
||||
- issue 206 and others: some improvements to packaging
|
||||
- fix issue127 and others: improve some docs
|
||||
- fix issue127 and others: improve some docs
|
||||
|
||||
See
|
||||
See
|
||||
|
||||
http://pytest.org/
|
||||
|
||||
@@ -26,7 +26,7 @@ holger krekel
|
||||
Changes between 2.3.1 and 2.3.2
|
||||
-----------------------------------
|
||||
|
||||
- fix issue208 and fix issue29 use new py version to avoid long pauses
|
||||
- fix issue208 and fix issue29 use new py version to avoid long pauses
|
||||
when printing tracebacks in long modules
|
||||
|
||||
- fix issue205 - conftests in subdirs customizing
|
||||
|
||||
@@ -6,7 +6,7 @@ which offers uebersimple assertions, scalable fixture mechanisms
|
||||
and deep customization for testing with Python. Particularly,
|
||||
this release provides:
|
||||
|
||||
- integration fixes and improvements related to flask, numpy, nose,
|
||||
- integration fixes and improvements related to flask, numpy, nose,
|
||||
unittest, mock
|
||||
|
||||
- makes pytest work on py24 again (yes, people sometimes still need to use it)
|
||||
@@ -16,7 +16,7 @@ this release provides:
|
||||
Thanks to Manuel Jacob, Thomas Waldmann, Ronny Pfannschmidt, Pavel Repin
|
||||
and Andreas Taumoefolau for providing patches and all for the issues.
|
||||
|
||||
See
|
||||
See
|
||||
|
||||
http://pytest.org/
|
||||
|
||||
@@ -59,4 +59,3 @@ Changes between 2.3.2 and 2.3.3
|
||||
|
||||
- fix issue127 - improve documentation for pytest_addoption() and
|
||||
add a ``config.getoption(name)`` helper function for consistency.
|
||||
|
||||
|
||||
@@ -10,15 +10,15 @@ comes with the following fixes and features:
|
||||
can write: -k "name1 or name2" etc. This is a slight usage incompatibility
|
||||
if you used special syntax like "TestClass.test_method" which you now
|
||||
need to write as -k "TestClass and test_method" to match a certain
|
||||
method in a certain test class.
|
||||
method in a certain test class.
|
||||
- allow to dynamically define markers via
|
||||
item.keywords[...]=assignment integrating with "-m" option
|
||||
- yielded test functions will now have autouse-fixtures active but
|
||||
- yielded test functions will now have autouse-fixtures active but
|
||||
cannot accept fixtures as funcargs - it's anyway recommended to
|
||||
rather use the post-2.0 parametrize features instead of yield, see:
|
||||
http://pytest.org/latest/example/parametrize.html
|
||||
- fix autouse-issue where autouse-fixtures would not be discovered
|
||||
if defined in a a/conftest.py file and tests in a/tests/test_some.py
|
||||
if defined in an a/conftest.py file and tests in a/tests/test_some.py
|
||||
- fix issue226 - LIFO ordering for fixture teardowns
|
||||
- fix issue224 - invocations with >256 char arguments now work
|
||||
- fix issue91 - add/discuss package/directory level setups in example
|
||||
@@ -26,7 +26,7 @@ comes with the following fixes and features:
|
||||
|
||||
Thanks in particular to Thomas Waldmann for spotting and reporting issues.
|
||||
|
||||
See
|
||||
See
|
||||
|
||||
http://pytest.org/
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ few interesting new plugins saw the light last month:
|
||||
- pytest-random: randomize test ordering
|
||||
|
||||
And several others like pytest-django saw maintenance releases.
|
||||
For a more complete list, check out
|
||||
https://pypi.python.org/pypi?%3Aaction=search&term=pytest&submit=search.
|
||||
For a more complete list, check out
|
||||
https://pypi.org/search/?q=pytest
|
||||
|
||||
For general information see:
|
||||
|
||||
@@ -81,7 +81,7 @@ Changes between 2.3.4 and 2.3.5
|
||||
- fix bug where using capsys with pytest.set_trace() in a test
|
||||
function would break when looking at capsys.readouterr()
|
||||
|
||||
- allow to specify prefixes starting with "_" when
|
||||
- allow to specify prefixes starting with "_" when
|
||||
customizing python_functions test discovery. (thanks Graham Horler)
|
||||
|
||||
- improve PYTEST_DEBUG tracing output by putting
|
||||
@@ -94,4 +94,3 @@ Changes between 2.3.4 and 2.3.5
|
||||
- fix issue134 - print the collect errors that prevent running specified test items
|
||||
|
||||
- fix issue266 - accept unicode in MarkEvaluator expressions
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
pytest-2.4.0: new fixture features/hooks and bug fixes
|
||||
===========================================================================
|
||||
|
||||
The just released pytest-2.4.0 brings many improvements and numerous
|
||||
The just released pytest-2.4.0 brings many improvements and numerous
|
||||
bug fixes while remaining plugin- and test-suite compatible apart
|
||||
from a few supposedly very minor incompatibilities. See below for
|
||||
from a few supposedly very minor incompatibilities. See below for
|
||||
a full list of details. A few feature highlights:
|
||||
|
||||
- new yield-style fixtures `pytest.yield_fixture
|
||||
@@ -13,7 +13,7 @@ a full list of details. A few feature highlights:
|
||||
- improved pdb support: ``import pdb ; pdb.set_trace()`` now works
|
||||
without requiring prior disabling of stdout/stderr capturing.
|
||||
Also the ``--pdb`` options works now on collection and internal errors
|
||||
and we introduced a new experimental hook for IDEs/plugins to
|
||||
and we introduced a new experimental hook for IDEs/plugins to
|
||||
intercept debugging: ``pytest_exception_interact(node, call, report)``.
|
||||
|
||||
- shorter monkeypatch variant to allow specifying an import path as
|
||||
@@ -23,21 +23,21 @@ a full list of details. A few feature highlights:
|
||||
called if the corresponding setup method succeeded.
|
||||
|
||||
- integrate tab-completion on command line options if you
|
||||
have `argcomplete <http://pypi.python.org/pypi/argcomplete>`_
|
||||
have `argcomplete <http://pypi.python.org/pypi/argcomplete>`_
|
||||
configured.
|
||||
|
||||
- allow boolean expression directly with skipif/xfail
|
||||
if a "reason" is also specified.
|
||||
|
||||
- a new hook ``pytest_load_initial_conftests`` allows plugins like
|
||||
`pytest-django <http://pypi.python.org/pypi/pytest-django>`_ to
|
||||
`pytest-django <https://pypi.org/project/pytest-django/>`_ to
|
||||
influence the environment before conftest files import ``django``.
|
||||
|
||||
- reporting: color the last line red or green depending if
|
||||
failures/errors occurred or everything passed.
|
||||
|
||||
The documentation has been updated to accommodate the changes,
|
||||
see `http://pytest.org <http://pytest.org>`_
|
||||
The documentation has been updated to accommodate the changes,
|
||||
see `http://pytest.org <http://pytest.org>`_
|
||||
|
||||
To install or upgrade pytest::
|
||||
|
||||
@@ -45,8 +45,8 @@ To install or upgrade pytest::
|
||||
easy_install -U pytest
|
||||
|
||||
|
||||
**Many thanks to all who helped, including Floris Bruynooghe,
|
||||
Brianna Laugher, Andreas Pelme, Anthon van der Neut, Anatoly Bubenkoff,
|
||||
**Many thanks to all who helped, including Floris Bruynooghe,
|
||||
Brianna Laugher, Andreas Pelme, Anthon van der Neut, Anatoly Bubenkoff,
|
||||
Vladimir Keleshev, Mathieu Agopian, Ronny Pfannschmidt, Christian
|
||||
Theunert and many others.**
|
||||
|
||||
@@ -101,12 +101,12 @@ new features:
|
||||
- make "import pdb ; pdb.set_trace()" work natively wrt capturing (no
|
||||
"-s" needed anymore), making ``pytest.set_trace()`` a mere shortcut.
|
||||
|
||||
- fix issue181: --pdb now also works on collect errors (and
|
||||
on internal errors) . This was implemented by a slight internal
|
||||
refactoring and the introduction of a new hook
|
||||
- fix issue181: --pdb now also works on collect errors (and
|
||||
on internal errors) . This was implemented by a slight internal
|
||||
refactoring and the introduction of a new hook
|
||||
``pytest_exception_interact`` hook (see next item).
|
||||
|
||||
- fix issue341: introduce new experimental hook for IDEs/terminals to
|
||||
- fix issue341: introduce new experimental hook for IDEs/terminals to
|
||||
intercept debugging: ``pytest_exception_interact(node, call, report)``.
|
||||
|
||||
- new monkeypatch.setattr() variant to provide a shorter
|
||||
@@ -124,7 +124,7 @@ new features:
|
||||
phase of a node.
|
||||
|
||||
- simplify pytest.mark.parametrize() signature: allow to pass a
|
||||
CSV-separated string to specify argnames. For example:
|
||||
CSV-separated string to specify argnames. For example:
|
||||
``pytest.mark.parametrize("input,expected", [(1,2), (2,3)])``
|
||||
works as well as the previous:
|
||||
``pytest.mark.parametrize(("input", "expected"), ...)``.
|
||||
@@ -149,10 +149,10 @@ new features:
|
||||
|
||||
Bug fixes:
|
||||
|
||||
- fix issue358 - capturing options are now parsed more properly
|
||||
- fix issue358 - capturing options are now parsed more properly
|
||||
by using a new parser.parse_known_args method.
|
||||
|
||||
- pytest now uses argparse instead of optparse (thanks Anthon) which
|
||||
- pytest now uses argparse instead of optparse (thanks Anthon) which
|
||||
means that "argparse" is added as a dependency if installing into python2.6
|
||||
environments or below.
|
||||
|
||||
@@ -193,7 +193,7 @@ Bug fixes:
|
||||
- fix issue323 - sorting of many module-scoped arg parametrizations
|
||||
|
||||
- make sessionfinish hooks execute with the same cwd-context as at
|
||||
session start (helps fix plugin behaviour which write output files
|
||||
session start (helps fix plugin behaviour which write output files
|
||||
with relative path such as pytest-cov)
|
||||
|
||||
- fix issue316 - properly reference collection hooks in docs
|
||||
@@ -201,7 +201,7 @@ Bug fixes:
|
||||
- fix issue 306 - cleanup of -k/-m options to only match markers/test
|
||||
names/keywords respectively. Thanks Wouter van Ackooy.
|
||||
|
||||
- improved doctest counting for doctests in python modules --
|
||||
- improved doctest counting for doctests in python modules --
|
||||
files without any doctest items will not show up anymore
|
||||
and doctest examples are counted as separate test items.
|
||||
thanks Danilo Bellini.
|
||||
@@ -211,7 +211,7 @@ Bug fixes:
|
||||
mode. Thanks Jason R. Coombs.
|
||||
|
||||
- fix junitxml generation when test output contains control characters,
|
||||
addressing issue267, thanks Jaap Broekhuizen
|
||||
addressing issue267, thanks Jaap Broekhuizen
|
||||
|
||||
- fix issue338: honor --tb style for setup/teardown errors as well. Thanks Maho.
|
||||
|
||||
@@ -220,6 +220,5 @@ Bug fixes:
|
||||
- better parametrize error messages, thanks Brianna Laugher
|
||||
|
||||
- pytest_terminal_summary(terminalreporter) hooks can now use
|
||||
".section(title)" and ".line(msg)" methods to print extra
|
||||
".section(title)" and ".line(msg)" methods to print extra
|
||||
information at the end of a test run.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ compared to 2.3.5 before they hit more people:
|
||||
"type" keyword should also be converted to the respective types.
|
||||
thanks Floris Bruynooghe, @dnozay. (fixes issue360 and issue362)
|
||||
|
||||
- fix dotted filename completion when using argcomplete
|
||||
- fix dotted filename completion when using argcomplete
|
||||
thanks Anthon van der Neuth. (fixes issue361)
|
||||
|
||||
- fix regression when a 1-tuple ("arg",) is used for specifying
|
||||
|
||||
@@ -26,9 +26,9 @@ pytest-2.4.2 is another bug-fixing release:
|
||||
|
||||
- remove attempt to "dup" stdout at startup as it's icky.
|
||||
the normal capturing should catch enough possibilities
|
||||
of tests messing up standard FDs.
|
||||
of tests messing up standard FDs.
|
||||
|
||||
- add pluginmanager.do_configure(config) as a link to
|
||||
- add pluginmanager.do_configure(config) as a link to
|
||||
config.do_configure() for plugin-compatibility
|
||||
|
||||
as usual, docs at http://pytest.org and upgrades via::
|
||||
|
||||
@@ -4,7 +4,7 @@ pytest-2.5.0: now down to ZERO reported bugs!
|
||||
pytest-2.5.0 is a big fixing release, the result of two community bug
|
||||
fixing days plus numerous additional works from many people and
|
||||
reporters. The release should be fully compatible to 2.4.2, existing
|
||||
plugins and test suites. We aim at maintaining this level of ZERO reported
|
||||
plugins and test suites. We aim at maintaining this level of ZERO reported
|
||||
bugs because it's no fun if your testing tool has bugs, is it? Under a
|
||||
condition, though: when submitting a bug report please provide
|
||||
clear information about the circumstances and a simple example which
|
||||
@@ -17,12 +17,12 @@ help.
|
||||
For those who use older Python versions, please note that pytest is not
|
||||
automatically tested on python2.5 due to virtualenv, setuptools and tox
|
||||
not supporting it anymore. Manual verification shows that it mostly
|
||||
works fine but it's not going to be part of the automated release
|
||||
works fine but it's not going to be part of the automated release
|
||||
process and thus likely to break in the future.
|
||||
|
||||
As usual, current docs are at
|
||||
As usual, current docs are at
|
||||
|
||||
http://pytest.org
|
||||
http://pytest.org
|
||||
|
||||
and you can upgrade from pypi via::
|
||||
|
||||
@@ -40,28 +40,28 @@ holger krekel
|
||||
2.5.0
|
||||
-----------------------------------
|
||||
|
||||
- dropped python2.5 from automated release testing of pytest itself
|
||||
which means it's probably going to break soon (but still works
|
||||
- dropped python2.5 from automated release testing of pytest itself
|
||||
which means it's probably going to break soon (but still works
|
||||
with this release we believe).
|
||||
|
||||
- simplified and fixed implementation for calling finalizers when
|
||||
parametrized fixtures or function arguments are involved. finalization
|
||||
parametrized fixtures or function arguments are involved. finalization
|
||||
is now performed lazily at setup time instead of in the "teardown phase".
|
||||
While this might sound odd at first, it helps to ensure that we are
|
||||
While this might sound odd at first, it helps to ensure that we are
|
||||
correctly handling setup/teardown even in complex code. User-level code
|
||||
should not be affected unless it's implementing the pytest_runtest_teardown
|
||||
hook and expecting certain fixture instances are torn down within (very
|
||||
unlikely and would have been unreliable anyway).
|
||||
|
||||
- PR90: add --color=yes|no|auto option to force terminal coloring
|
||||
- PR90: add --color=yes|no|auto option to force terminal coloring
|
||||
mode ("auto" is default). Thanks Marc Abramowitz.
|
||||
|
||||
- fix issue319 - correctly show unicode in assertion errors. Many
|
||||
thanks to Floris Bruynooghe for the complete PR. Also means
|
||||
we depend on py>=1.4.19 now.
|
||||
|
||||
- fix issue396 - correctly sort and finalize class-scoped parametrized
|
||||
tests independently from number of methods on the class.
|
||||
- fix issue396 - correctly sort and finalize class-scoped parametrized
|
||||
tests independently from number of methods on the class.
|
||||
|
||||
- refix issue323 in a better way -- parametrization should now never
|
||||
cause Runtime Recursion errors because the underlying algorithm
|
||||
@@ -70,18 +70,18 @@ holger krekel
|
||||
to problems for more than >966 non-function scoped parameters).
|
||||
|
||||
- fix issue290 - there is preliminary support now for parametrizing
|
||||
with repeated same values (sometimes useful to test if calling
|
||||
with repeated same values (sometimes useful to test if calling
|
||||
a second time works as with the first time).
|
||||
|
||||
- close issue240 - document precisely how pytest module importing
|
||||
works, discuss the two common test directory layouts, and how it
|
||||
works, discuss the two common test directory layouts, and how it
|
||||
interacts with PEP420-namespace packages.
|
||||
|
||||
- fix issue246 fix finalizer order to be LIFO on independent fixtures
|
||||
depending on a parametrized higher-than-function scoped fixture.
|
||||
depending on a parametrized higher-than-function scoped fixture.
|
||||
(was quite some effort so please bear with the complexity of this sentence :)
|
||||
Thanks Ralph Schmitt for the precise failure example.
|
||||
|
||||
|
||||
- fix issue244 by implementing special index for parameters to only use
|
||||
indices for paramentrized test ids
|
||||
|
||||
@@ -99,9 +99,9 @@ holger krekel
|
||||
filtering with simple strings that are not valid python expressions.
|
||||
Examples: "-k 1.3" matches all tests parametrized with 1.3.
|
||||
"-k None" filters all tests that have "None" in their name
|
||||
and conversely "-k 'not None'".
|
||||
and conversely "-k 'not None'".
|
||||
Previously these examples would raise syntax errors.
|
||||
|
||||
|
||||
- fix issue384 by removing the trial support code
|
||||
since the unittest compat enhancements allow
|
||||
trial to handle it on its own
|
||||
@@ -109,7 +109,7 @@ holger krekel
|
||||
- don't hide an ImportError when importing a plugin produces one.
|
||||
fixes issue375.
|
||||
|
||||
- fix issue275 - allow usefixtures and autouse fixtures
|
||||
- fix issue275 - allow usefixtures and autouse fixtures
|
||||
for running doctest text files.
|
||||
|
||||
- fix issue380 by making --resultlog only rely on longrepr instead
|
||||
@@ -135,20 +135,20 @@ holger krekel
|
||||
(it already did neutralize pytest.mark.xfail markers)
|
||||
|
||||
- refine pytest / pkg_resources interactions: The AssertionRewritingHook
|
||||
PEP302 compliant loader now registers itself with setuptools/pkg_resources
|
||||
PEP302 compliant loader now registers itself with setuptools/pkg_resources
|
||||
properly so that the pkg_resources.resource_stream method works properly.
|
||||
Fixes issue366. Thanks for the investigations and full PR to Jason R. Coombs.
|
||||
|
||||
- pytestconfig fixture is now session-scoped as it is the same object during the
|
||||
whole test run. Fixes issue370.
|
||||
whole test run. Fixes issue370.
|
||||
|
||||
- avoid one surprising case of marker malfunction/confusion::
|
||||
|
||||
|
||||
@pytest.mark.some(lambda arg: ...)
|
||||
def test_function():
|
||||
|
||||
would not work correctly because pytest assumes @pytest.mark.some
|
||||
gets a function to be decorated already. We now at least detect if this
|
||||
would not work correctly because pytest assumes @pytest.mark.some
|
||||
gets a function to be decorated already. We now at least detect if this
|
||||
arg is a lambda and thus the example will work. Thanks Alex Gaynor
|
||||
for bringing it up.
|
||||
|
||||
@@ -159,11 +159,11 @@ holger krekel
|
||||
although it's not needed by pytest itself atm. Also
|
||||
fix caching. Fixes issue376.
|
||||
|
||||
- fix issue221 - handle importing of namespace-package with no
|
||||
- fix issue221 - handle importing of namespace-package with no
|
||||
__init__.py properly.
|
||||
|
||||
- refactor internal FixtureRequest handling to avoid monkeypatching.
|
||||
One of the positive user-facing effects is that the "request" object
|
||||
One of the positive user-facing effects is that the "request" object
|
||||
can now be used in closures.
|
||||
|
||||
- fixed version comparison in pytest.importskip(modname, minverstring)
|
||||
@@ -172,4 +172,3 @@ holger krekel
|
||||
does not duplicate the unittest-API into the "plain" namespace.
|
||||
|
||||
- fix verbose reporting for @mock'd test functions
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
pytest-2.5.1: fixes and new home page styling
|
||||
===========================================================================
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
pytest is a mature Python testing tool with more than a 1000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
The 2.5.1 release maintains the "zero-reported-bugs" promise by fixing
|
||||
the three bugs reported since the last release a few days ago. It also
|
||||
@@ -11,12 +11,12 @@ the flask theme from Armin Ronacher:
|
||||
|
||||
http://pytest.org
|
||||
|
||||
If you have anything more to improve styling and docs,
|
||||
If you have anything more to improve styling and docs,
|
||||
we'd be very happy to merge further pull requests.
|
||||
|
||||
On the coding side, the release also contains a little enhancement to
|
||||
fixture decorators allowing to directly influence generation of test
|
||||
ids, thanks to Floris Bruynooghe. Other thanks for helping with
|
||||
ids, thanks to Floris Bruynooghe. Other thanks for helping with
|
||||
this release go to Anatoly Bubenkoff and Ronny Pfannschmidt.
|
||||
|
||||
As usual, you can upgrade from pypi via::
|
||||
@@ -37,11 +37,10 @@ holger krekel
|
||||
|
||||
- Allow parameterized fixtures to specify the ID of the parameters by
|
||||
adding an ids argument to pytest.fixture() and pytest.yield_fixture().
|
||||
Thanks Floris Bruynooghe.
|
||||
Thanks Floris Bruynooghe.
|
||||
|
||||
- fix issue404 by always using the binary xml escape in the junitxml
|
||||
plugin. Thanks Ronny Pfannschmidt.
|
||||
|
||||
- fix issue407: fix addoption docstring to point to argparse instead of
|
||||
optparse. Thanks Daniel D. Wright.
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
pytest-2.5.2: fixes
|
||||
pytest-2.5.2: fixes
|
||||
===========================================================================
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
pytest is a mature Python testing tool with more than a 1000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
The 2.5.2 release fixes a few bugs with two maybe-bugs remaining and
|
||||
actively being worked on (and waiting for the bug reporter's input).
|
||||
@@ -19,18 +19,18 @@ As usual, you can upgrade from pypi via::
|
||||
|
||||
Thanks to the following people who contributed to this release:
|
||||
|
||||
Anatoly Bubenkov
|
||||
Anatoly Bubenkov
|
||||
Ronny Pfannschmidt
|
||||
Floris Bruynooghe
|
||||
Bruno Oliveira
|
||||
Andreas Pelme
|
||||
Bruno Oliveira
|
||||
Andreas Pelme
|
||||
Jurko Gospodnetić
|
||||
Piotr Banaszkiewicz
|
||||
Simon Liedtke
|
||||
lakka
|
||||
Lukasz Balcerzak
|
||||
Philippe Muller
|
||||
Daniel Hahler
|
||||
Piotr Banaszkiewicz
|
||||
Simon Liedtke
|
||||
lakka
|
||||
Lukasz Balcerzak
|
||||
Philippe Muller
|
||||
Daniel Hahler
|
||||
|
||||
have fun,
|
||||
holger krekel
|
||||
@@ -39,11 +39,11 @@ holger krekel
|
||||
-----------------------------------
|
||||
|
||||
- fix issue409 -- better interoperate with cx_freeze by not
|
||||
trying to import from collections.abc which causes problems
|
||||
trying to import from collections.abc which causes problems
|
||||
for py27/cx_freeze. Thanks Wolfgang L. for reporting and tracking it down.
|
||||
|
||||
- fixed docs and code to use "pytest" instead of "py.test" almost everywhere.
|
||||
Thanks Jurko Gospodnetic for the complete PR.
|
||||
Thanks Jurko Gospodnetic for the complete PR.
|
||||
|
||||
- fix issue425: mention at end of "py.test -h" that --markers
|
||||
and --fixtures work according to specified test path (or current dir)
|
||||
@@ -54,11 +54,10 @@ holger krekel
|
||||
|
||||
- copy, cleanup and integrate py.io capture
|
||||
from pylib 1.4.20.dev2 (rev 13d9af95547e)
|
||||
|
||||
|
||||
- address issue416: clarify docs as to conftest.py loading semantics
|
||||
|
||||
- fix issue429: comparing byte strings with non-ascii chars in assert
|
||||
expressions now work better. Thanks Floris Bruynooghe.
|
||||
|
||||
- make capfd/capsys.capture private, its unused and shouldn't be exposed
|
||||
|
||||
|
||||
@@ -52,8 +52,7 @@ Changes 2.6.1
|
||||
"::" node id specifications (copy pasted from "-v" output)
|
||||
|
||||
- fix issue544 by only removing "@NUM" at the end of "::" separated parts
|
||||
and if the part has an ".py" extension
|
||||
and if the part has a ".py" extension
|
||||
|
||||
- don't use py.std import helper, rather import things directly.
|
||||
Thanks Bruno Oliveira.
|
||||
|
||||
|
||||
@@ -49,4 +49,3 @@ holger krekel
|
||||
- Do not mark as universal wheel because Python 2.6 is different from
|
||||
other builds due to the extra argparse dependency. Fixes issue566.
|
||||
Thanks sontek.
|
||||
|
||||
|
||||
@@ -49,4 +49,3 @@ Changes 2.6.3
|
||||
|
||||
- check xfail/skip also with non-python function test items. Thanks
|
||||
Floris Bruynooghe.
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ holger krekel
|
||||
- fix issue655: work around different ways that cause python2/3
|
||||
to leak sys.exc_info into fixtures/tests causing failures in 3rd party code
|
||||
|
||||
- fix issue615: assertion re-writing did not correctly escape % signs
|
||||
- fix issue615: assertion rewriting did not correctly escape % signs
|
||||
when formatting boolean operations, which tripped over mixing
|
||||
booleans with modulo operators. Thanks to Tom Viner for the report,
|
||||
triaging and fix.
|
||||
@@ -98,4 +98,3 @@ holger krekel
|
||||
- On failure, the ``sys.last_value``, ``sys.last_type`` and
|
||||
``sys.last_traceback`` are set, so that a user can inspect the error
|
||||
via postmortem debugging (almarklein).
|
||||
|
||||
|
||||
@@ -55,4 +55,3 @@ The py.test Development Team
|
||||
|
||||
- fix issue756, fix issue752 (and similar issues): depend on py-1.4.29
|
||||
which has a refined algorithm for traceback generation.
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ The py.test Development Team
|
||||
Thanks Gabriel Reis for the PR.
|
||||
|
||||
- add more talks to the documentation
|
||||
- extend documentation on the --ignore cli option
|
||||
- use pytest-runner for setuptools integration
|
||||
- extend documentation on the --ignore cli option
|
||||
- use pytest-runner for setuptools integration
|
||||
- minor fixes for interaction with OS X El Capitan system integrity protection (thanks Florian)
|
||||
|
||||
|
||||
@@ -28,4 +28,4 @@ The py.test Development Team
|
||||
2.8.7 (compared to 2.8.6)
|
||||
-------------------------
|
||||
|
||||
- fix #1338: use predictable object resolution for monkeypatch
|
||||
- fix #1338: use predictable object resolution for monkeypatch
|
||||
|
||||
@@ -14,25 +14,25 @@ As usual, you can upgrade from pypi via::
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
Anatoly Bubenkov
|
||||
Bruno Oliveira
|
||||
Buck Golemon
|
||||
David Vierra
|
||||
Florian Bruhin
|
||||
Galaczi Endre
|
||||
Georgy Dyuldin
|
||||
Lukas Bednar
|
||||
Luke Murphy
|
||||
Marcin Biernat
|
||||
Matt Williams
|
||||
Michael Aquilina
|
||||
Raphael Pierzina
|
||||
Ronny Pfannschmidt
|
||||
Ryan Wooden
|
||||
Tiemo Kieft
|
||||
TomV
|
||||
holger krekel
|
||||
jab
|
||||
Anatoly Bubenkov
|
||||
Bruno Oliveira
|
||||
Buck Golemon
|
||||
David Vierra
|
||||
Florian Bruhin
|
||||
Galaczi Endre
|
||||
Georgy Dyuldin
|
||||
Lukas Bednar
|
||||
Luke Murphy
|
||||
Marcin Biernat
|
||||
Matt Williams
|
||||
Michael Aquilina
|
||||
Raphael Pierzina
|
||||
Ronny Pfannschmidt
|
||||
Ryan Wooden
|
||||
Tiemo Kieft
|
||||
TomV
|
||||
holger krekel
|
||||
jab
|
||||
|
||||
|
||||
Happy testing,
|
||||
@@ -76,18 +76,18 @@ The py.test Development Team
|
||||
**Changes**
|
||||
|
||||
* **Important**: `py.code <https://pylib.readthedocs.io/en/latest/code.html>`_ has been
|
||||
merged into the ``pytest`` repository as ``pytest._code``. This decision
|
||||
was made because ``py.code`` had very few uses outside ``pytest`` and the
|
||||
fact that it was in a different repository made it difficult to fix bugs on
|
||||
merged into the ``pytest`` repository as ``pytest._code``. This decision
|
||||
was made because ``py.code`` had very few uses outside ``pytest`` and the
|
||||
fact that it was in a different repository made it difficult to fix bugs on
|
||||
its code in a timely manner. The team hopes with this to be able to better
|
||||
refactor out and improve that code.
|
||||
This change shouldn't affect users, but it is useful to let users aware
|
||||
if they encounter any strange behavior.
|
||||
|
||||
Keep in mind that the code for ``pytest._code`` is **private** and
|
||||
|
||||
Keep in mind that the code for ``pytest._code`` is **private** and
|
||||
**experimental**, so you definitely should not import it explicitly!
|
||||
|
||||
Please note that the original ``py.code`` is still available in
|
||||
Please note that the original ``py.code`` is still available in
|
||||
`pylib <https://pylib.readthedocs.io>`_.
|
||||
|
||||
* ``pytest_enter_pdb`` now optionally receives the pytest config object.
|
||||
@@ -129,8 +129,8 @@ The py.test Development Team
|
||||
|
||||
* Fix (`#1422`_): junit record_xml_property doesn't allow multiple records
|
||||
with same name.
|
||||
|
||||
|
||||
|
||||
|
||||
.. _`traceback style docs`: https://pytest.org/latest/usage.html#modifying-python-traceback-printing
|
||||
|
||||
.. _#1422: https://github.com/pytest-dev/pytest/issues/1422
|
||||
@@ -156,4 +156,4 @@ The py.test Development Team
|
||||
.. _@tomviner: https://github.com/tomviner
|
||||
.. _@RonnyPfannschmidt: https://github.com/RonnyPfannschmidt
|
||||
.. _@rabbbit: https://github.com/rabbbit
|
||||
.. _@hackebrot: https://github.com/hackebrot
|
||||
.. _@hackebrot: https://github.com/hackebrot
|
||||
|
||||
@@ -14,17 +14,17 @@ As usual, you can upgrade from pypi via::
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
Bruno Oliveira
|
||||
Daniel Hahler
|
||||
Dmitry Malinovsky
|
||||
Florian Bruhin
|
||||
Floris Bruynooghe
|
||||
Matt Bachmann
|
||||
Ronny Pfannschmidt
|
||||
TomV
|
||||
Vladimir Bolshakov
|
||||
Zearin
|
||||
palaviv
|
||||
Bruno Oliveira
|
||||
Daniel Hahler
|
||||
Dmitry Malinovsky
|
||||
Florian Bruhin
|
||||
Floris Bruynooghe
|
||||
Matt Bachmann
|
||||
Ronny Pfannschmidt
|
||||
TomV
|
||||
Vladimir Bolshakov
|
||||
Zearin
|
||||
palaviv
|
||||
|
||||
|
||||
Happy testing,
|
||||
|
||||
@@ -8,10 +8,10 @@ against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a lot of bugs fixes and improvements, and much of
|
||||
the work done on it was possible because of the 2016 Sprint[1], which
|
||||
was funded by an indiegogo campaign which raised over US$12,000 with
|
||||
nearly 100 backers.
|
||||
was funded by an indiegogo campaign which raised over US$12,000 with
|
||||
nearly 100 backers.
|
||||
|
||||
There's a "What's new in pytest 3.0" [2] blog post highlighting the
|
||||
There's a "What's new in pytest 3.0" [2] blog post highlighting the
|
||||
major features in this release.
|
||||
|
||||
To see the complete changelog and documentation, please visit:
|
||||
|
||||
@@ -7,7 +7,7 @@ This release fixes some regressions reported in version 3.0.0, being a
|
||||
drop-in replacement. To upgrade:
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
|
||||
The changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
@@ -7,7 +7,7 @@ This release fixes some regressions and bugs reported in version 3.0.1, being a
|
||||
drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
|
||||
The changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
@@ -3,11 +3,11 @@ pytest-3.0.3
|
||||
|
||||
pytest 3.0.3 has just been released to PyPI.
|
||||
|
||||
This release fixes some regressions and bugs reported in the last version,
|
||||
This release fixes some regressions and bugs reported in the last version,
|
||||
being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
|
||||
The changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
@@ -3,11 +3,11 @@ pytest-3.0.4
|
||||
|
||||
pytest 3.0.4 has just been released to PyPI.
|
||||
|
||||
This release fixes some regressions and bugs reported in the last version,
|
||||
This release fixes some regressions and bugs reported in the last version,
|
||||
being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
|
||||
The changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
@@ -6,7 +6,7 @@ pytest 3.0.5 has just been released to PyPI.
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
|
||||
The changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
@@ -6,7 +6,7 @@ pytest 3.0.6 has just been released to PyPI.
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
|
||||
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ pytest 3.0.7 has just been released to PyPI.
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
|
||||
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
@@ -6,7 +6,7 @@ pytest 3.1.1 has just been released to PyPI.
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
|
||||
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
@@ -6,7 +6,7 @@ pytest 3.1.2 has just been released to PyPI.
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
|
||||
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
@@ -6,7 +6,7 @@ pytest 3.1.3 has just been released to PyPI.
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
|
||||
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
@@ -6,7 +6,7 @@ pytest 3.2.1 has just been released to PyPI.
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
|
||||
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
@@ -6,7 +6,7 @@ pytest 3.2.2 has just been released to PyPI.
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
|
||||
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
@@ -6,7 +6,7 @@ pytest 3.2.3 has just been released to PyPI.
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
|
||||
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
@@ -6,7 +6,7 @@ pytest 3.2.4 has just been released to PyPI.
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
|
||||
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
18
doc/en/announce/release-3.2.5.rst
Normal file
18
doc/en/announce/release-3.2.5.rst
Normal file
@@ -0,0 +1,18 @@
|
||||
pytest-3.2.5
|
||||
=======================================
|
||||
|
||||
pytest 3.2.5 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
* Bruno Oliveira
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
50
doc/en/announce/release-3.3.0.rst
Normal file
50
doc/en/announce/release-3.3.0.rst
Normal file
@@ -0,0 +1,50 @@
|
||||
pytest-3.3.0
|
||||
=======================================
|
||||
|
||||
The pytest team is proud to announce the 3.3.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1600 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
to take a look at the CHANGELOG:
|
||||
|
||||
http://doc.pytest.org/en/latest/changelog.html
|
||||
|
||||
For complete documentation, please visit:
|
||||
|
||||
http://docs.pytest.org
|
||||
|
||||
As usual, you can upgrade from pypi via:
|
||||
|
||||
pip install -U pytest
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
* Anthony Sottile
|
||||
* Bruno Oliveira
|
||||
* Ceridwen
|
||||
* Daniel Hahler
|
||||
* Dirk Thomas
|
||||
* Dmitry Malinovsky
|
||||
* Florian Bruhin
|
||||
* George Y. Kussumoto
|
||||
* Hugo
|
||||
* Jesús Espino
|
||||
* Joan Massich
|
||||
* Ofir
|
||||
* OfirOshir
|
||||
* Ronny Pfannschmidt
|
||||
* Samuel Dion-Girardeau
|
||||
* Srinivas Reddy Thatiparthy
|
||||
* Sviatoslav Abakumov
|
||||
* Tarcisio Fischer
|
||||
* Thomas Hisch
|
||||
* Tyler Goodlet
|
||||
* hugovk
|
||||
* je
|
||||
* prokaktus
|
||||
|
||||
|
||||
Happy testing,
|
||||
The Pytest Development Team
|
||||
25
doc/en/announce/release-3.3.1.rst
Normal file
25
doc/en/announce/release-3.3.1.rst
Normal file
@@ -0,0 +1,25 @@
|
||||
pytest-3.3.1
|
||||
=======================================
|
||||
|
||||
pytest 3.3.1 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
* Bruno Oliveira
|
||||
* Daniel Hahler
|
||||
* Eugene Prikazchikov
|
||||
* Florian Bruhin
|
||||
* Roland Puntaier
|
||||
* Ronny Pfannschmidt
|
||||
* Sebastian Rahlf
|
||||
* Tom Viner
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
28
doc/en/announce/release-3.3.2.rst
Normal file
28
doc/en/announce/release-3.3.2.rst
Normal file
@@ -0,0 +1,28 @@
|
||||
pytest-3.3.2
|
||||
=======================================
|
||||
|
||||
pytest 3.3.2 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
* Anthony Sottile
|
||||
* Antony Lee
|
||||
* Austin
|
||||
* Bruno Oliveira
|
||||
* Florian Bruhin
|
||||
* Floris Bruynooghe
|
||||
* Henk-Jaap Wagenaar
|
||||
* Jurko Gospodnetić
|
||||
* Ronny Pfannschmidt
|
||||
* Srinivas Reddy Thatiparthy
|
||||
* Thomas Hisch
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
52
doc/en/announce/release-3.4.0.rst
Normal file
52
doc/en/announce/release-3.4.0.rst
Normal file
@@ -0,0 +1,52 @@
|
||||
pytest-3.4.0
|
||||
=======================================
|
||||
|
||||
The pytest team is proud to announce the 3.4.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1600 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
to take a look at the CHANGELOG:
|
||||
|
||||
http://doc.pytest.org/en/latest/changelog.html
|
||||
|
||||
For complete documentation, please visit:
|
||||
|
||||
http://docs.pytest.org
|
||||
|
||||
As usual, you can upgrade from pypi via:
|
||||
|
||||
pip install -U pytest
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
* Aaron
|
||||
* Alan Velasco
|
||||
* Anders Hovmöller
|
||||
* Andrew Toolan
|
||||
* Anthony Sottile
|
||||
* Aron Coyle
|
||||
* Brian Maissy
|
||||
* Bruno Oliveira
|
||||
* Cyrus Maden
|
||||
* Florian Bruhin
|
||||
* Henk-Jaap Wagenaar
|
||||
* Ian Lesperance
|
||||
* Jon Dufresne
|
||||
* Jurko Gospodnetić
|
||||
* Kate
|
||||
* Kimberly
|
||||
* Per A. Brodtkorb
|
||||
* Pierre-Alexandre Fonta
|
||||
* Raphael Castaneda
|
||||
* Ronny Pfannschmidt
|
||||
* ST John
|
||||
* Segev Finer
|
||||
* Thomas Hisch
|
||||
* Tzu-ping Chung
|
||||
* feuillemorte
|
||||
|
||||
|
||||
Happy testing,
|
||||
The Pytest Development Team
|
||||
27
doc/en/announce/release-3.4.1.rst
Normal file
27
doc/en/announce/release-3.4.1.rst
Normal file
@@ -0,0 +1,27 @@
|
||||
pytest-3.4.1
|
||||
=======================================
|
||||
|
||||
pytest 3.4.1 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
* Aaron
|
||||
* Alan Velasco
|
||||
* Andy Freeland
|
||||
* Brian Maissy
|
||||
* Bruno Oliveira
|
||||
* Florian Bruhin
|
||||
* Jason R. Coombs
|
||||
* Marcin Bachry
|
||||
* Pedro Algarvio
|
||||
* Ronny Pfannschmidt
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
28
doc/en/announce/release-3.4.2.rst
Normal file
28
doc/en/announce/release-3.4.2.rst
Normal file
@@ -0,0 +1,28 @@
|
||||
pytest-3.4.2
|
||||
=======================================
|
||||
|
||||
pytest 3.4.2 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
* Allan Feldman
|
||||
* Bruno Oliveira
|
||||
* Florian Bruhin
|
||||
* Jason R. Coombs
|
||||
* Kyle Altendorf
|
||||
* Maik Figura
|
||||
* Ronny Pfannschmidt
|
||||
* codetriage-readme-bot
|
||||
* feuillemorte
|
||||
* joshm91
|
||||
* mike
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
51
doc/en/announce/release-3.5.0.rst
Normal file
51
doc/en/announce/release-3.5.0.rst
Normal file
@@ -0,0 +1,51 @@
|
||||
pytest-3.5.0
|
||||
=======================================
|
||||
|
||||
The pytest team is proud to announce the 3.5.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1600 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
to take a look at the CHANGELOG:
|
||||
|
||||
http://doc.pytest.org/en/latest/changelog.html
|
||||
|
||||
For complete documentation, please visit:
|
||||
|
||||
http://docs.pytest.org
|
||||
|
||||
As usual, you can upgrade from pypi via:
|
||||
|
||||
pip install -U pytest
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
* Allan Feldman
|
||||
* Brian Maissy
|
||||
* Bruno Oliveira
|
||||
* Carlos Jenkins
|
||||
* Daniel Hahler
|
||||
* Florian Bruhin
|
||||
* Jason R. Coombs
|
||||
* Jeffrey Rackauckas
|
||||
* Jordan Speicher
|
||||
* Julien Palard
|
||||
* Kale Kundert
|
||||
* Kostis Anagnostopoulos
|
||||
* Kyle Altendorf
|
||||
* Maik Figura
|
||||
* Pedro Algarvio
|
||||
* Ronny Pfannschmidt
|
||||
* Tadeu Manoel
|
||||
* Tareq Alayan
|
||||
* Thomas Hisch
|
||||
* William Lee
|
||||
* codetriage-readme-bot
|
||||
* feuillemorte
|
||||
* joshm91
|
||||
* mike
|
||||
|
||||
|
||||
Happy testing,
|
||||
The Pytest Development Team
|
||||
30
doc/en/announce/release-3.5.1.rst
Normal file
30
doc/en/announce/release-3.5.1.rst
Normal file
@@ -0,0 +1,30 @@
|
||||
pytest-3.5.1
|
||||
=======================================
|
||||
|
||||
pytest 3.5.1 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
* Brian Maissy
|
||||
* Bruno Oliveira
|
||||
* Darren Burns
|
||||
* David Chudzicki
|
||||
* Floris Bruynooghe
|
||||
* Holger Kohr
|
||||
* Irmen de Jong
|
||||
* Jeffrey Rackauckas
|
||||
* Rachel Kogan
|
||||
* Ronny Pfannschmidt
|
||||
* Stefan Scherfke
|
||||
* Tim Strazny
|
||||
* Семён Марьясин
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
41
doc/en/announce/release-3.6.0.rst
Normal file
41
doc/en/announce/release-3.6.0.rst
Normal file
@@ -0,0 +1,41 @@
|
||||
pytest-3.6.0
|
||||
=======================================
|
||||
|
||||
The pytest team is proud to announce the 3.6.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1600 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
to take a look at the CHANGELOG:
|
||||
|
||||
http://doc.pytest.org/en/latest/changelog.html
|
||||
|
||||
For complete documentation, please visit:
|
||||
|
||||
http://docs.pytest.org
|
||||
|
||||
As usual, you can upgrade from pypi via:
|
||||
|
||||
pip install -U pytest
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
* Anthony Shaw
|
||||
* ApaDoctor
|
||||
* Brian Maissy
|
||||
* Bruno Oliveira
|
||||
* Jon Dufresne
|
||||
* Katerina Koukiou
|
||||
* Miro Hrončok
|
||||
* Rachel Kogan
|
||||
* Ronny Pfannschmidt
|
||||
* Tim Hughes
|
||||
* Tyler Goodlet
|
||||
* Ville Skyttä
|
||||
* aviral1701
|
||||
* feuillemorte
|
||||
|
||||
|
||||
Happy testing,
|
||||
The Pytest Development Team
|
||||
24
doc/en/announce/release-3.6.1.rst
Normal file
24
doc/en/announce/release-3.6.1.rst
Normal file
@@ -0,0 +1,24 @@
|
||||
pytest-3.6.1
|
||||
=======================================
|
||||
|
||||
pytest 3.6.1 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
* Anthony Sottile
|
||||
* Bruno Oliveira
|
||||
* Jeffrey Rackauckas
|
||||
* Miro Hrončok
|
||||
* Niklas Meinzer
|
||||
* Oliver Bestwalter
|
||||
* Ronny Pfannschmidt
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
@@ -25,23 +25,23 @@ to assert that your function returns a certain value. If this assertion fails
|
||||
you will see the return value of the function call::
|
||||
|
||||
$ pytest test_assert1.py
|
||||
======= test session starts ========
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
|
||||
rootdir: $REGENDOC_TMPDIR, inifile:
|
||||
collected 1 item
|
||||
|
||||
test_assert1.py F
|
||||
|
||||
======= FAILURES ========
|
||||
_______ test_function ________
|
||||
|
||||
|
||||
test_assert1.py F [100%]
|
||||
|
||||
================================= FAILURES =================================
|
||||
______________________________ test_function _______________________________
|
||||
|
||||
def test_function():
|
||||
> assert f() == 4
|
||||
E assert 3 == 4
|
||||
E + where 3 = f()
|
||||
|
||||
|
||||
test_assert1.py:5: AssertionError
|
||||
======= 1 failed in 0.12 seconds ========
|
||||
========================= 1 failed in 0.12 seconds =========================
|
||||
|
||||
``pytest`` has support for showing the values of the most common subexpressions
|
||||
including calls, attributes, comparisons, and binary and unary
|
||||
@@ -168,16 +168,16 @@ when it encounters comparisons. For example::
|
||||
if you run this module::
|
||||
|
||||
$ pytest test_assert2.py
|
||||
======= test session starts ========
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
|
||||
rootdir: $REGENDOC_TMPDIR, inifile:
|
||||
collected 1 item
|
||||
|
||||
test_assert2.py F
|
||||
|
||||
======= FAILURES ========
|
||||
_______ test_set_comparison ________
|
||||
|
||||
|
||||
test_assert2.py F [100%]
|
||||
|
||||
================================= FAILURES =================================
|
||||
___________________________ test_set_comparison ____________________________
|
||||
|
||||
def test_set_comparison():
|
||||
set1 = set("1308")
|
||||
set2 = set("8035")
|
||||
@@ -188,9 +188,9 @@ if you run this module::
|
||||
E Extra items in the right set:
|
||||
E '5'
|
||||
E Use -v to get the full diff
|
||||
|
||||
|
||||
test_assert2.py:5: AssertionError
|
||||
======= 1 failed in 0.12 seconds ========
|
||||
========================= 1 failed in 0.12 seconds =========================
|
||||
|
||||
Special comparisons are done for a number of cases:
|
||||
|
||||
@@ -209,7 +209,7 @@ the ``pytest_assertrepr_compare`` hook.
|
||||
.. autofunction:: _pytest.hookspec.pytest_assertrepr_compare
|
||||
:noindex:
|
||||
|
||||
As an example consider adding the following hook in a :ref:`conftest.py <conftest.py>`
|
||||
As an example consider adding the following hook in a :ref:`conftest.py <conftest.py>`
|
||||
file which provides an alternative explanation for ``Foo`` objects::
|
||||
|
||||
# content of conftest.py
|
||||
@@ -238,17 +238,17 @@ you can run the test module and get the custom output defined in
|
||||
the conftest file::
|
||||
|
||||
$ pytest -q test_foocompare.py
|
||||
F
|
||||
======= FAILURES ========
|
||||
_______ test_compare ________
|
||||
|
||||
F [100%]
|
||||
================================= FAILURES =================================
|
||||
_______________________________ test_compare _______________________________
|
||||
|
||||
def test_compare():
|
||||
f1 = Foo(1)
|
||||
f2 = Foo(2)
|
||||
> assert f1 == f2
|
||||
E assert Comparing Foo instances:
|
||||
E vals: 1 != 2
|
||||
|
||||
|
||||
test_foocompare.py:11: AssertionError
|
||||
1 failed in 0.12 seconds
|
||||
|
||||
|
||||
@@ -10,3 +10,11 @@ With the pytest 3.0 release we introduced a clear communication scheme for when
|
||||
To communicate changes we are already issuing deprecation warnings, but they are not displayed by default. In pytest 3.0 we changed the default setting so that pytest deprecation warnings are displayed if not explicitly silenced (with ``--disable-pytest-warnings``).
|
||||
|
||||
We will only remove deprecated functionality in major releases (e.g. if we deprecate something in 3.0 we will remove it in 4.0), and keep it around for at least two minor releases (e.g. if we deprecate something in 3.9 and 4.0 is the next release, we will not remove it in 4.0 but in 5.0).
|
||||
|
||||
|
||||
Deprecation Roadmap
|
||||
-------------------
|
||||
|
||||
We track deprecation and removal of features using milestones and the `deprecation <https://github.com/pytest-dev/pytest/issues?q=label%3A%22type%3A+deprecation%22>`_ and `removal <https://github.com/pytest-dev/pytest/labels/type%3A%20removal>`_ labels on GitHub.
|
||||
|
||||
Following our deprecation policy, after starting issuing deprecation warnings we keep features for *at least* two minor versions before considering removal.
|
||||
|
||||
@@ -14,7 +14,7 @@ Install argcomplete using::
|
||||
|
||||
For global activation of all argcomplete enabled python applications run::
|
||||
|
||||
sudo activate-global-python-argcomplete
|
||||
sudo activate-global-python-argcomplete
|
||||
|
||||
For permanent (but not global) ``pytest`` activation, use::
|
||||
|
||||
@@ -23,6 +23,3 @@ For permanent (but not global) ``pytest`` activation, use::
|
||||
For one-time activation of argcomplete for ``pytest`` only, use::
|
||||
|
||||
eval "$(register-python-argcomplete pytest)"
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,113 +1,90 @@
|
||||
:orphan:
|
||||
|
||||
.. _`pytest helpers`:
|
||||
|
||||
Pytest API and builtin fixtures
|
||||
================================================
|
||||
|
||||
This is a list of ``pytest.*`` API functions and fixtures.
|
||||
|
||||
Most of the information of this page has been moved over to :ref:`reference`.
|
||||
|
||||
For information on plugin hooks and objects, see :ref:`plugins`.
|
||||
|
||||
For information on the ``pytest.mark`` mechanism, see :ref:`mark`.
|
||||
|
||||
For the below objects, you can also interactively ask for help, e.g. by
|
||||
typing on the Python interactive prompt something like::
|
||||
|
||||
import pytest
|
||||
help(pytest)
|
||||
|
||||
.. currentmodule:: pytest
|
||||
|
||||
Invoking pytest interactively
|
||||
---------------------------------------------------
|
||||
|
||||
.. autofunction:: main
|
||||
|
||||
More examples at :ref:`pytest.main-usage`
|
||||
|
||||
|
||||
Helpers for assertions about Exceptions/Warnings
|
||||
--------------------------------------------------------
|
||||
|
||||
.. autofunction:: raises
|
||||
|
||||
Examples at :ref:`assertraises`.
|
||||
|
||||
.. autofunction:: deprecated_call
|
||||
|
||||
Comparing floating point numbers
|
||||
--------------------------------
|
||||
|
||||
.. autofunction:: approx
|
||||
|
||||
Raising a specific test outcome
|
||||
--------------------------------------
|
||||
|
||||
You can use the following functions in your test, fixture or setup
|
||||
functions to force a certain test outcome. Note that most often
|
||||
you can rather use declarative marks, see :ref:`skipping`.
|
||||
|
||||
.. autofunction:: _pytest.outcomes.fail
|
||||
.. autofunction:: _pytest.outcomes.skip
|
||||
.. autofunction:: _pytest.outcomes.importorskip
|
||||
.. autofunction:: _pytest.outcomes.xfail
|
||||
.. autofunction:: _pytest.outcomes.exit
|
||||
|
||||
Fixtures and requests
|
||||
-----------------------------------------------------
|
||||
|
||||
To mark a fixture function:
|
||||
|
||||
.. autofunction:: _pytest.fixtures.fixture
|
||||
|
||||
Tutorial at :ref:`fixtures`.
|
||||
|
||||
The ``request`` object that can be used from fixture functions.
|
||||
|
||||
.. autoclass:: _pytest.fixtures.FixtureRequest()
|
||||
:members:
|
||||
|
||||
|
||||
.. _builtinfixtures:
|
||||
.. _builtinfuncargs:
|
||||
|
||||
Builtin fixtures/function arguments
|
||||
-----------------------------------------
|
||||
|
||||
You can ask for available builtin or project-custom
|
||||
:ref:`fixtures <fixtures>` by typing::
|
||||
For information about fixtures, see :ref:`fixtures`. To see a complete list of available fixtures (add ``-v`` to also see fixtures with leading ``_``), type ::
|
||||
|
||||
$ pytest -q --fixtures
|
||||
cache
|
||||
Return a cache object that can persist state between testing sessions.
|
||||
|
||||
|
||||
cache.get(key, default)
|
||||
cache.set(key, value)
|
||||
|
||||
|
||||
Keys must be a ``/`` separated value, where the first part is usually the
|
||||
name of your plugin or application to avoid clashes with other cache users.
|
||||
|
||||
|
||||
Values can be any object handled by the json stdlib module.
|
||||
capsys
|
||||
Enable capturing of writes to sys.stdout/sys.stderr and make
|
||||
Enable capturing of writes to ``sys.stdout`` and ``sys.stderr`` and make
|
||||
captured output available via ``capsys.readouterr()`` method calls
|
||||
which return a ``(out, err)`` tuple.
|
||||
which return a ``(out, err)`` namedtuple. ``out`` and ``err`` will be ``text``
|
||||
objects.
|
||||
capsysbinary
|
||||
Enable capturing of writes to ``sys.stdout`` and ``sys.stderr`` and make
|
||||
captured output available via ``capsys.readouterr()`` method calls
|
||||
which return a ``(out, err)`` tuple. ``out`` and ``err`` will be ``bytes``
|
||||
objects.
|
||||
capfd
|
||||
Enable capturing of writes to file descriptors 1 and 2 and make
|
||||
Enable capturing of writes to file descriptors ``1`` and ``2`` and make
|
||||
captured output available via ``capfd.readouterr()`` method calls
|
||||
which return a ``(out, err)`` tuple.
|
||||
which return a ``(out, err)`` tuple. ``out`` and ``err`` will be ``text``
|
||||
objects.
|
||||
capfdbinary
|
||||
Enable capturing of write to file descriptors 1 and 2 and make
|
||||
captured output available via ``capfdbinary.readouterr`` method calls
|
||||
which return a ``(out, err)`` tuple. ``out`` and ``err`` will be
|
||||
``bytes`` objects.
|
||||
doctest_namespace
|
||||
Inject names into the doctest namespace.
|
||||
Fixture that returns a :py:class:`dict` that will be injected into the namespace of doctests.
|
||||
pytestconfig
|
||||
the pytest config object with access to command line opts.
|
||||
record_xml_property
|
||||
Add extra xml properties to the tag for the calling test.
|
||||
Session-scoped fixture that returns the :class:`_pytest.config.Config` object.
|
||||
|
||||
Example::
|
||||
|
||||
def test_foo(pytestconfig):
|
||||
if pytestconfig.getoption("verbose"):
|
||||
...
|
||||
record_property
|
||||
Add an extra properties the calling test.
|
||||
User properties become part of the test report and are available to the
|
||||
configured reporters, like JUnit XML.
|
||||
The fixture is callable with ``(name, value)``, with value being automatically
|
||||
xml-encoded.
|
||||
|
||||
Example::
|
||||
|
||||
def test_function(record_property):
|
||||
record_property("example_key", 1)
|
||||
record_xml_property
|
||||
(Deprecated) use record_property.
|
||||
record_xml_attribute
|
||||
Add extra xml attributes to the tag for the calling test.
|
||||
The fixture is callable with ``(name, value)``, with value being
|
||||
automatically xml-encoded
|
||||
caplog
|
||||
Access and control log capturing.
|
||||
|
||||
Captured logs are available through the following methods::
|
||||
|
||||
* caplog.text -> string containing formatted log output
|
||||
* caplog.records -> list of logging.LogRecord instances
|
||||
* caplog.record_tuples -> list of (logger_name, level, message) tuples
|
||||
* caplog.clear() -> clear captured records and formatted log output string
|
||||
monkeypatch
|
||||
The returned ``monkeypatch`` fixture provides these
|
||||
helper methods to modify objects, dictionaries or os.environ::
|
||||
|
||||
|
||||
monkeypatch.setattr(obj, name, value, raising=True)
|
||||
monkeypatch.delattr(obj, name, raising=True)
|
||||
monkeypatch.setitem(mapping, name, value)
|
||||
@@ -116,17 +93,14 @@ You can ask for available builtin or project-custom
|
||||
monkeypatch.delenv(name, value, raising=True)
|
||||
monkeypatch.syspath_prepend(path)
|
||||
monkeypatch.chdir(path)
|
||||
|
||||
|
||||
All modifications will be undone after the requesting
|
||||
test function or fixture has finished. The ``raising``
|
||||
parameter determines if a KeyError or AttributeError
|
||||
will be raised if the set/deletion operation has no target.
|
||||
recwarn
|
||||
Return a WarningsRecorder instance that provides these methods:
|
||||
|
||||
* ``pop(category=None)``: return last warning matching the category.
|
||||
* ``clear()``: clear list of warnings
|
||||
|
||||
Return a :class:`WarningsRecorder` instance that records all warnings emitted by test functions.
|
||||
|
||||
See http://docs.python.org/library/warnings.html for information
|
||||
on warning categories.
|
||||
tmpdir_factory
|
||||
@@ -137,5 +111,12 @@ You can ask for available builtin or project-custom
|
||||
created as a sub directory of the base temporary
|
||||
directory. The returned object is a `py.path.local`_
|
||||
path object.
|
||||
|
||||
|
||||
.. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html
|
||||
|
||||
no tests ran in 0.12 seconds
|
||||
|
||||
You can also interactively ask for help, e.g. by typing on the Python interactive prompt something like::
|
||||
|
||||
import pytest
|
||||
help(pytest)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user