From 3de9bdb7f27ae6abf1125fdf1b1fcc391f477332 Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Wed, 18 Apr 2018 09:49:16 +0200 Subject: [PATCH 1/7] tests: tweak `simplewheel` test distribution - change module name to prevent conflicts with other distributions - add a `__version__` field for version checks --- .../simplewheel-1.0-py2.py3-none-any.whl | Bin 1759 -> 1842 bytes .../simplewheel-2.0-1-py2.py3-none-any.whl | Bin 1754 -> 1872 bytes .../simplewheel-2.0-py2.py3-none-any.whl | Bin 1754 -> 1835 bytes tests/data/src/simplewheel-1.0/setup.cfg | 0 tests/data/src/simplewheel-1.0/setup.py | 8 +++++--- .../src/simplewheel-1.0/simple/__init__.py | 1 - .../simplewheel-1.0/simplewheel/__init__.py | 1 + tests/data/src/simplewheel-2.0/setup.cfg | 0 tests/data/src/simplewheel-2.0/setup.py | 8 +++++--- .../src/simplewheel-2.0/simple/__init__.py | 1 - .../simplewheel-2.0/simplewheel/__init__.py | 1 + tests/functional/test_install.py | 4 ++-- 12 files changed, 14 insertions(+), 10 deletions(-) create mode 100644 tests/data/src/simplewheel-1.0/setup.cfg delete mode 100644 tests/data/src/simplewheel-1.0/simple/__init__.py create mode 100644 tests/data/src/simplewheel-1.0/simplewheel/__init__.py create mode 100644 tests/data/src/simplewheel-2.0/setup.cfg delete mode 100644 tests/data/src/simplewheel-2.0/simple/__init__.py create mode 100644 tests/data/src/simplewheel-2.0/simplewheel/__init__.py diff --git a/tests/data/packages/simplewheel-1.0-py2.py3-none-any.whl b/tests/data/packages/simplewheel-1.0-py2.py3-none-any.whl index 0e6b91eea8572528b8b5c599f2688ff0ab13ff76..02ce1f7ac5e984eb9b21d1a968497ee3ee14254d 100644 GIT binary patch literal 1842 zcmWIWW@Zs#U|`^2Q1YMXlPiBQObo~aiHHMnab|8oPHK5ZYHE&te0*kJW=VX!UO{Dd zzrMGw*10q1yZgg8ga(*jF%Edn#1H^Cs(RZ*pE%w6OFTd$xPVv_)hJyJS)!o$>g?(&4JWOC4-Ai_ZERH2JQ=3D^nKnU)}xQl zoiRWB&Bak;Z(e}4wpY5K4%Ztgh1ETCe)frr`=v=Xrk6PJv}Sx+@^VAbG%bgfultw8 z+??eSotZFY-`$mYn{C(e|NJ*ae9o_i6p6MQHO$;`i#}@>g<37B2w^BSODs95F?(61 zaQhS&&36wDM{Hl96Pc+u*Kzi;HuG6eE=VcYe*b=q->(112PV{TJfHd{mJjGzP*~#k zbV+_ed`@avYK~q>MTz#gGrA`{bvi^|&!!*^O)cN2T%JDLgEUr{TsnLDy!Tb#Gpk!VC6rxupd}lIH(eghKsTKS zVkNw8^K}hzba4!EjP2da2aMk4?>4US3LFxf6(uG#G#t5Kqt)hiN;R-Z^wsUlD_7ol zbADS*(}nJqFU&i4Nce1y)0wK;mf7|A$;Y=0>z7rS9=kqo=BI>NyKQfLzPze7<%NrU z$d;E&yMNx#Hn5C;d2uU8s@d&@TW+dK?*C%O<|t4reQ8bMN0s+8b_$tteq~0Dv8Y#F zd>Ozb>c+&tpn%s4L9WjJK`yluPZl*fFu1&5`N_ZGgu)A%q6EpKyaJv*I|DSDd-%G~ zD4f2oZaL%5j`F?NW6yeo1>IR9arwG|isi#Zjj3}FT;f=9D|+iy;b)oOGFMF#(0Wn9 zzM|;n-sFZ~ellnL0;X3MW4C{Ft?H?@Rr?2`{aJj{XRK zFv~I4`qs0W6`5J@r$(%ulzpb`4}*i<)``a7gWqOl{Rratv>>6I>Fy=wzn*?8E`61= z^V_oc{+g>-XSFrH(|h;#j2Ku+#cuuod&`JbSyy_LLy$v)@XJ7cH5^`RT(Np3fS66)Lfj6YYO~5Z32N zw_bj2sx#}#ab(rIv#WpY(zU9&)?#&^oNMByC?4haQN8zXuhXKdIok@S zm^N+Pq)GP6j4dBoCvx z6{TQ7Hx#`vK^XcBuc6?g1>G?8+>bD<37DC1yAW0upqq!D6%ppSGUGE3k}(6kS=m53 O*n!XxX#Z;#5Dx%J%$79( literal 1759 zcmWIWW@Zs#U|`^2(62IZY-nN);{@{9fmjHLi!*Zza#Ho<<1_OzOXB183MzyBG|!%0 z`-F)h0Io4>?^c&M-TF&BKn+|#tO?gxo{^fGqid*VpqG+aT%wzqmzJ;Z;u`E6F=jkR9wRS_4BvS{NEoxdW3G|?!=}q{XnC(0paO67{l*^YeUre7O%9 z2)O+Bx;eS2B`QDes8`_aM2dn%2YZ`}AI$9(-@g-S#^ zbHoz0oqe%9!EJBfZLyrzUL2V@wIeYmMPXCPlbY*~UN_!2)MC47W1H{aBQE$~ZLjOj7kk&Oi+XYYW|5V&J!&vD$w=IRg)e?T zmE;%1=cJaU=IE7FlxUwjqkF>hDS8O?)bFf`0fr0+%i|59a1U2kAMW!WzGpA;dh2SP zJ9B<>kiiw>2Sxs8y>-2GPU>$8^6)yTqt~g=zB2HF!3ATZYsMFzaGg4@fAOo%HC_!} zud^q8HU(*DYWY6p^7Pprq_M)}(%IAJy|4P7S^Wef>Wmb8@(O?sS_{NVcpc{J8sg~U z7~=TZSJ%_WQ^)fP!g-gBAAIsY5k-3J2NBC z(M?VIYKG&HcymR6`%>|Dd7JFN&JAuC+rCZd``fX=SW{~P)6aTm%v^T(qKtR; z)2TLJmV|xMdTO68yTWeK2JTDD=XCkYH|Op-&#=?4;M38z+g|nmFT~&UH@?85dqJ!+ z>zH|E(C*M{&Y64IBj@z=JHEcJemnPqo>My8b;EO=g-;uHRk>|m)~jVS$tyuP`cK95 zv$IS;hi{aB6x44oqn>B>tkP?7LcvaZhhSUqnGFG# zmc>_DgkR6mym!~+0b@n&5B diff --git a/tests/data/packages/simplewheel-2.0-1-py2.py3-none-any.whl b/tests/data/packages/simplewheel-2.0-1-py2.py3-none-any.whl index acf0c56cfd9a7258f4aa0ff3fec937ee26447f91..cd34cf8a0463fea5047ffc1a8b67362646d3c7a3 100644 GIT binary patch literal 1872 zcmWIWW@Zs#U|`^2$oHSe#l4K5@GBmw13iZ~?J4s!_T|dIq|NdMTO3 zCAyh;Y5DptuEEYho&h1A{(gEz#UWU?(pK(nI$&+7*y?1&_Nb~R!dZ1ez+3-G z+g_IBNiR&C^6yR0?RS2&lS?haO&8lKbQ-FClI5vry!QNr@2ZABUl}sGBR#`ab)Q$p zEmzbG_@Ms7;L)@#XTs*4P7k=X^~2gU%aSPW`~LT4TzSln8jj~vzr^wZy$T9TLS8P( zFNn`cElbVOE2${aK6gg?Cc*cmFa1U2kA8wE_ z7kMGEzB$O?it&RY|Fhn@UOFfBHwAfkoz&6m)MsBAc){R;vDpRV3s1OCo!7tkRp%P7 zhOXDylRle*G&Hq*pB8DIJ>$tJbwG5|jJ%}*0hvo?PoF=1)$AGJoWh1~9R-YNX{aW7 z!KwzJ^UedY3IS*Ox`sHqIEFaJ_U`3kG8Aa}ZQ~lJpfv5J3%6r$Q~lSXzBq;1Eh+pv zw_iUsr_A{N8G~w$yPhXv0$2H8e04Nuos8j{b@Pf3tY&Ze)#=Y{JoVzM?%TT#pIzyj zG{eW=WQ)ua|EKq*4SrsDajv|h)F^s!+0pc$H8VrInlzr-Jo9`k;UTxOK>3yS6=~Gi zyMAvDPYy7#1~D-(C=u{MkgKzQkW1^tlSNGq3@-0io|>;Pai&7SiN*sB8cj_}PmEe~ znm6$n?D+8Yh3!i^OtHr)wP2%LI#_qwQbKA-sbU-oxcK3wiRpzeBJ&2_G6zSSqw^HKS_ z*B|blXDhO9n=D&;+VS5DRf^@+lBUm{RCo9r!<9=imTm57>bcXN@v8q>9Iyi)$?wh z7u;08J#qewB`t9k{13L~*f%qBz2DZ&ky2i4)5ka|NXETw>q8dDO22hMVyc4OKZ5UH z;dhRi*e1Gb^J~7ppCsN*YTg^ASRT;Ad}A@9`x-#H-Fb^6PsX*Rq6 z{tI^Dj@%}@!^Mj!w=4fw#kvz^sMOm9T;V-9+@Pi7+vc8NZ2; Vj2ht0$_CQI4urNqH~eJ*@c;y}o6i6M literal 1754 zcmWIWW@Zs#U|`^2(62IZY-nN);{@{9fmjHLi!*Zza#Ho<<1_OzOXB183MzyBG|!%0 z`-F)h0IpGU?^c&M-TF&BKn+|#tO?gxo{^fGqidvRpqG+aT%wzqmzJ;Z;u`E6F=jkR9wRS_4BvS{NEoxdW3FdwzSgbUZ7E1fmj`{k-4cQi7AOCiF#SZ`FXKDzTAfl z1YG`m-JIOi5|kfz)miY;BX&9O95G%K&y#tgnt$Jy9i4o<@^hNohK;f|Y798PD#&nbkV4iz73qb|glnDr_owQgi>|>&6=gdu%stZ1eqm#AScw!lIS$ zBn%|`Ja3$}di2ctwAfCqYg+MLF3sQ7_PXwT(Y$V5)QkH!zc8W(Qj?6t9a!k%_fbiH zL3~bXS!#}6NkxhFxih*aJfEV6Pfz{MniycXfUrE?@Co;Db@kys@8Ns)BCofu*10q1 zHwPJ9F@8|wf7V;qOXsBirXUZmlRA2x`s^zMFBn`fHo9hf;R)BN^ZFOR>RjX1(Dgcd z(q~hUhNhP9Q!Y=R?LitVOfH>0ect=3@0rz4Fe0v3-~CfA&_Qc~SP8Ggd|g8vT^vIk zKl|!>`grPiUO_nTlJSF2-e-Kb25EqOuM2YhL#K&+dS}o2>a5xl!~sn=pH7_jy{hZs z=OI(-TW8-ua$;*uA!5bE?Vf5vuo4;4&RnH)4S$>xRhBM z-J#AWYFn_fn7_L?Y<6AQ^JyPXieBG*SY<+W;&Q!>>LN_cEe}-h??3GSBYAy>&liz* z?gc$fQ9Q0!9@WY-t2hnB^3* zeryF4L^lJ&mPSjsejRj7DpK73d~2iT?otY=;op4LWFsr@R|q7lL6kWY#<%%K&S&$KZ6Ct F0{}u2WP$(y diff --git a/tests/data/packages/simplewheel-2.0-py2.py3-none-any.whl b/tests/data/packages/simplewheel-2.0-py2.py3-none-any.whl index acf0c56cfd9a7258f4aa0ff3fec937ee26447f91..5a352c4fe466189eb781cc2f9f12a64647076547 100644 GIT binary patch literal 1835 zcmWIWW@Zs#U|`^2$oHSfpACK5@GBmw13iZ~?ISYz@=f(D)<~n2`;99>lWvRl#7w6XQ(s0tUE09bw&R9@6!RKnwr}t`60=wq? zwwNy2(Q={UX+Y#*>1+X>qBpV=N*(ob&cD)D?ru6@ZK>GmWW@HUswTo&bwR*e|4G|k zmgGqsc5|R{DkkShCg2!GP)x@!&P;kSH>+@ z)C~Bb{=?wWv@K`C=ABLtxV81e+BD0ODDM0I_hwvq%#Ip{=TpDL@&P>x3P=1NF3B&5 z&q*yy&Cx5VDA7K5M)!oL?s*U2vk%e3@Y~%>`{IGd864*LXE_ zz0RKW*%YLqspb2W%hP9jkj4s=OJ`4?_rB_TW_3%agtE&Hv?NoLykJ!W&`sxoSP8G& zd|g8vT^vIkV|({(htIC`O`753Z?Z*ZiT~64 z(gr^-yf|0hQEC*uxa?^9&zhN`T}>L#Y@T^Omhg~US)lw%`-(JbbiLj5c5MbQZMrcr zFeu=4e~_!Qe~?S<#FIr$4h$~uSDu=$aM6*4&r(1lMV2R{Cq^ShLL##D;M>=eyHEC3 zU$4GpHI8i$xlZKP>Fu^>6pZBf(!a@4G0- zah$x~6|kaf`<2kuPY(R~n)>7TSqA&(hO#$$%$C$%PF%ryEiLtXZLo7XqImQk&*`B{E*?TxQFYvi|{`ulA8k2P-}Y3)uCJ)c*<{=$)Isp6b`AsZf) zee|uLQku?G`sPu;JKvH!e0dkVZyP=pd+_xsFjFxyi7?|X<$zHI1`UlM3Moe*mwCvB zU@PAsMldimGx`UtO~;Bp1sF!ZdCFsu%knQ*%hRuG_@hn^J?=GighGY^t61H4(;Kswlg&=6?< I6BZB;0Ap33kpKVy literal 1754 zcmWIWW@Zs#U|`^2(62IZY-nN);{@{9fmjHLi!*Zza#Ho<<1_OzOXB183MzyBG|!%0 z`-F)h0IpGU?^c&M-TF&BKn+|#tO?gxo{^fGqidvRpqG+aT%wzqmzJ;Z;u`E6F=jkR9wRS_4BvS{NEoxdW3FdwzSgbUZ7E1fmj`{k-4cQi7AOCiF#SZ`FXKDzTAfl z1YG`m-JIOi5|kfz)miY;BX&9O95G%K&y#tgnt$Jy9i4o<@^hNohK;f|Y798PD#&nbkV4iz73qb|glnDr_owQgi>|>&6=gdu%stZ1eqm#AScw!lIS$ zBn%|`Ja3$}di2ctwAfCqYg+MLF3sQ7_PXwT(Y$V5)QkH!zc8W(Qj?6t9a!k%_fbiH zL3~bXS!#}6NkxhFxih*aJfEV6Pfz{MniycXfUrE?@Co;Db@kys@8Ns)BCofu*10q1 zHwPJ9F@8|wf7V;qOXsBirXUZmlRA2x`s^zMFBn`fHo9hf;R)BN^ZFOR>RjX1(Dgcd z(q~hUhNhP9Q!Y=R?LitVOfH>0ect=3@0rz4Fe0v3-~CfA&_Qc~SP8Ggd|g8vT^vIk zKl|!>`grPiUO_nTlJSF2-e-Kb25EqOuM2YhL#K&+dS}o2>a5xl!~sn=pH7_jy{hZs z=OI(-TW8-ua$;*uA!5bE?Vf5vuo4;4&RnH)4S$>xRhBM z-J#AWYFn_fn7_L?Y<6AQ^JyPXieBG*SY<+W;&Q!>>LN_cEe}-h??3GSBYAy>&liz* z?gc$fQ9Q0!9@WY-t2hnB^3* zeryF4L^lJ&mPSjsejRj7DpK73d~2iT?otY=;op4LWFsr@R|q7lL6kWY#<%%K&S&$KZ6Ct F0{}u2WP$(y diff --git a/tests/data/src/simplewheel-1.0/setup.cfg b/tests/data/src/simplewheel-1.0/setup.cfg new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/data/src/simplewheel-1.0/setup.py b/tests/data/src/simplewheel-1.0/setup.py index f54a4502c5d..461536dce68 100644 --- a/tests/data/src/simplewheel-1.0/setup.py +++ b/tests/data/src/simplewheel-1.0/setup.py @@ -1,7 +1,9 @@ #!/usr/bin/env python -from setuptools import find_packages, setup +from setuptools import setup + +import simplewheel setup(name='simplewheel', - version='1.0', - packages=find_packages() + version=simplewheel.__version__, + packages=['simplewheel'], ) diff --git a/tests/data/src/simplewheel-1.0/simple/__init__.py b/tests/data/src/simplewheel-1.0/simple/__init__.py deleted file mode 100644 index 792d6005489..00000000000 --- a/tests/data/src/simplewheel-1.0/simple/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# diff --git a/tests/data/src/simplewheel-1.0/simplewheel/__init__.py b/tests/data/src/simplewheel-1.0/simplewheel/__init__.py new file mode 100644 index 00000000000..7e49527e386 --- /dev/null +++ b/tests/data/src/simplewheel-1.0/simplewheel/__init__.py @@ -0,0 +1 @@ +__version__ = '1.0' diff --git a/tests/data/src/simplewheel-2.0/setup.cfg b/tests/data/src/simplewheel-2.0/setup.cfg new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/data/src/simplewheel-2.0/setup.py b/tests/data/src/simplewheel-2.0/setup.py index e889bb6446e..461536dce68 100644 --- a/tests/data/src/simplewheel-2.0/setup.py +++ b/tests/data/src/simplewheel-2.0/setup.py @@ -1,7 +1,9 @@ #!/usr/bin/env python -from setuptools import find_packages, setup +from setuptools import setup + +import simplewheel setup(name='simplewheel', - version='2.0', - packages=find_packages() + version=simplewheel.__version__, + packages=['simplewheel'], ) diff --git a/tests/data/src/simplewheel-2.0/simple/__init__.py b/tests/data/src/simplewheel-2.0/simple/__init__.py deleted file mode 100644 index 792d6005489..00000000000 --- a/tests/data/src/simplewheel-2.0/simple/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# diff --git a/tests/data/src/simplewheel-2.0/simplewheel/__init__.py b/tests/data/src/simplewheel-2.0/simplewheel/__init__.py new file mode 100644 index 00000000000..3b3dacb9af5 --- /dev/null +++ b/tests/data/src/simplewheel-2.0/simplewheel/__init__.py @@ -0,0 +1 @@ +__version__ = '2.0' diff --git a/tests/functional/test_install.py b/tests/functional/test_install.py index ac704f1d607..603cf734c4b 100644 --- a/tests/functional/test_install.py +++ b/tests/functional/test_install.py @@ -197,8 +197,8 @@ def test_install_editable_uninstalls_existing_from_path(script, data): to_install = data.src.join('simplewheel-1.0') result = script.pip_install_local(to_install) assert 'Successfully installed simplewheel' in result.stdout - simple_folder = script.site_packages / 'simple' - result.assert_installed('simple', editable=False) + simple_folder = script.site_packages / 'simplewheel' + result.assert_installed('simplewheel', editable=False) assert simple_folder in result.files_created, str(result.stdout) result = script.pip( From 04874e24fd958537a5c3d1995f28879f470aa579 Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Wed, 18 Apr 2018 09:52:25 +0200 Subject: [PATCH 2/7] tests: improve PEP 518 tests - avoid hitting the index: use `common_wheels`/`script.pip_install_local` - use `script.pip(..., use_module=True)` to simplify some tests - improve `test_pep518_uses_build_env` parametrization - simplify `test_pep518_with_user_pip`: we only need to check build requirements can be installed, so no need for testing with both `install` and `wheel` command - fix `test_pip_wheel_with_pep518_build_reqs_no_isolation`: building pep518-3.0 without isolation should fail if the build requirements are not installed. --- tests/data/packages/pep518-3.0.tar.gz | Bin 853 -> 805 bytes .../{simple/__init__.py => pep518.py} | 0 tests/data/src/pep518-3.0/setup.cfg | 5 --- tests/data/src/pep518-3.0/setup.py | 6 +-- tests/functional/test_install.py | 42 ++++++++---------- tests/functional/test_wheel.py | 19 ++++---- 6 files changed, 31 insertions(+), 41 deletions(-) rename tests/data/src/pep518-3.0/{simple/__init__.py => pep518.py} (100%) diff --git a/tests/data/packages/pep518-3.0.tar.gz b/tests/data/packages/pep518-3.0.tar.gz index f912e6d85a2e689bb46f266d6571fbbf8714a36a..e88cb0baa51dfe6024cebd7caea6be48de0aa2bd 100644 GIT binary patch literal 805 zcmV+=1KRu_iwFqI`qo+k|72-%bT4paa5XVFEi*1KE_7jX0PUGuPunmQ$NTJ0;gttA ziKKR}6H*@#V;f==w8Hj)swy<6C0j0@|`jC)*ktBgEx9Mr`pm+4SN8V=%7$TTJJ+)J)i%c$$4M>70u4g|)BS`aK zw!MLTBqO2pyNul|Rgfy)&%Y z>c1KN&lGRuWv(C@5DDLkNJ8E{Yv)lSV)%Xm5O=$l$=X}AJqr;k%i?@Gnys}5=pFv2 z_%F)F>wnAVRs456?F**)KgasN5jI|Qid=TiqqGC*r7i<>sh*Ot%o19QooZK*Nj0A# zq#D%@g3=ADi}^wV4M9K}LOLpGq&KGe?~P*!37KtvnFa}TH|M8rbBoX!m-7xocT*q3 z>q$`#lPoOasWYlJ464Of=yX;e|7W+RP6&-@LfBcU{vX!=^(^jS|Mwr;e`WpPhxdPd zn_KArn*jU2=>PA~zskfghD(S|^+T<-|HJ%6{aeg;u>aej{ZTTg{~P-6ADw>O-Ru9Y z`v0K*(_&xJKWEtgX(s;HAN|PH0T3lw`WjSq2FP70BDv@6+*qqC#9AQXkxEgp%J#ZI?;`#A}aP}B`r69hZIm&TVUjgJ54;y5O; zjo+)LruREdp-WuXEq*17zr{5+4b#M?K~4YVrAB5mm9lBnU#b3|=KrNDaKZn-u>B__CTv33IP(I^uDK?DiDvx2j%)VM z{l9Bs3;cf@fTsulzeN8hhac60;r?;s`JZXJ3;MU@1?ayGj)?FlzVOwrB;hn-+X!oV zR~h;t*+%7x=qh((W;+^_f?|}@ zFb+uH^C+Xj^W^^bL{(m&4QziFAU|JMrVmnjV73L{Y%=Rx#GQ0Fk{7{omDlZO4E7;QNmu9RTRR75&R{&&$ibi>@O4 znOC?2G(crbW(Gty^s>e0%uC3e=D9%G3jy}c>A!)kmA~fyRsCG^>TITwEtDKN~ft%qnWk6^Rof0n4 z>`Jv9%S8#9$&@1Z8u{GfrVS Date: Wed, 18 Apr 2018 10:10:10 +0200 Subject: [PATCH 3/7] improve handling of PEP 518 build requirements Offload more work to the underlying pip command used to install the build requirements, so there's no need to duplicate code to handle environment markers/extras. This is done by setting the correct options from the finder passed in argument to `_install_build_reqs`. --- docs/reference/pip.rst | 49 ++++++++---------- news/5230.bugfix | 1 + news/5265.bugfix | 1 + src/pip/_internal/operations/prepare.py | 31 ++++++----- .../pep518_with_extra_and_markers-1.0.tar.gz | Bin 0 -> 926 bytes .../packages4/simple-1.0-py2.py3-none-any.whl | Bin 0 -> 1745 bytes .../MANIFEST.in | 1 + .../pep518_with_extra_and_markers.py | 1 + .../pyproject.toml | 7 +++ .../setup.cfg | 0 .../setup.py | 15 ++++++ tests/functional/test_install.py | 13 +++++ tests/lib/__init__.py | 8 +++ 13 files changed, 86 insertions(+), 41 deletions(-) create mode 100644 news/5230.bugfix create mode 100644 news/5265.bugfix create mode 100644 tests/data/packages/pep518_with_extra_and_markers-1.0.tar.gz create mode 100644 tests/data/packages4/simple-1.0-py2.py3-none-any.whl create mode 100644 tests/data/src/pep518_with_extra_and_markers-1.0/MANIFEST.in create mode 100644 tests/data/src/pep518_with_extra_and_markers-1.0/pep518_with_extra_and_markers.py create mode 100644 tests/data/src/pep518_with_extra_and_markers-1.0/pyproject.toml create mode 100644 tests/data/src/pep518_with_extra_and_markers-1.0/setup.cfg create mode 100644 tests/data/src/pep518_with_extra_and_markers-1.0/setup.py diff --git a/docs/reference/pip.rst b/docs/reference/pip.rst index 190ff90454d..306925f76ca 100644 --- a/docs/reference/pip.rst +++ b/docs/reference/pip.rst @@ -116,23 +116,10 @@ using an incorrect encoding (mojibake). PEP 518 Support ~~~~~~~~~~~~~~~ -Pip supports projects declaring dependencies that are required at install time -using a ``pyproject.toml`` file, in the form described in `PEP518`_. When -building a project, pip will install the required dependencies locally, and -make them available to the build process. - -As noted in the PEP, the minimum requirements for pip to be able to build a -project are:: - - [build-system] - # Minimum requirements for the build system to execute. - requires = ["setuptools", "wheel"] - -``setuptools`` and ``wheel`` **must** be included in any ``pyproject.toml`` -provided by a project - pip will assume these as a default, but will not add -them to an explicitly supplied list in a project supplied ``pyproject.toml`` -file. Once `PEP517`_ support is added, this restriction will be lifted and -alternative build tools will be allowed. +As of 10.0, pip supports projects declaring dependencies that are required at +install time using a ``pyproject.toml`` file, in the form described in +`PEP518`_. When building a project, pip will install the required dependencies +locally, and make them available to the build process. When making build requirements available, pip does so in an *isolated environment*. That is, pip does not install those requirements into the user's @@ -152,17 +139,23 @@ appropriately. .. _pep-518-limitations: -The current implementation of `PEP518`_ in pip requires that any dependencies -specified in ``pyproject.toml`` are available as wheels. This is a technical -limitation of the implementation - dependencies only available as source would -require a build step of their own, which would recursively invoke the `PEP518`_ -dependency installation process. The potentially unbounded recursion involved -was not considered acceptable, and so installation of build dependencies from -source has been disabled until a safe resolution of this issue has been found. - -Further, it also doesn't support the use of environment markers and extras, -only version specifiers are respected. Support for markers and extras will be -added in a future release. +**Limitations**: + +* until `PEP517`_ support is added, ``setuptools`` and ``wheel`` **must** be + included in the list of build requirements: pip will assume these as default, + but will not automatically add them to the list of build requirements if + explicitly defined in ``pyproject.toml``. + +* the current implementation only support installing build requirements from + wheels: this is a technical limitation of the implementation - source + installs would require a build step of their own, potentially recursively + triggering another `PEP518`_ dependency installation process. The possible + unbounded recursion involved was not considered acceptable, and so + installation of build dependencies from source has been disabled until a safe + resolution of this issue is found. + +* ``pip<18.0`` does not support the use of environment markers and extras, only + version specifiers are respected. .. _PEP517: http://www.python.org/dev/peps/pep-0517/ .. _PEP518: http://www.python.org/dev/peps/pep-0518/ diff --git a/news/5230.bugfix b/news/5230.bugfix new file mode 100644 index 00000000000..9f34eddf52c --- /dev/null +++ b/news/5230.bugfix @@ -0,0 +1 @@ +Improve handling of PEP 518 build requirements: support environment markers and extras. diff --git a/news/5265.bugfix b/news/5265.bugfix new file mode 100644 index 00000000000..9f34eddf52c --- /dev/null +++ b/news/5265.bugfix @@ -0,0 +1 @@ +Improve handling of PEP 518 build requirements: support environment markers and extras. diff --git a/src/pip/_internal/operations/prepare.py b/src/pip/_internal/operations/prepare.py index 27e3a5dd32e..d2331b69e26 100644 --- a/src/pip/_internal/operations/prepare.py +++ b/src/pip/_internal/operations/prepare.py @@ -1,11 +1,9 @@ """Prepares a distribution for installation """ -import itertools import logging import os import sys -from copy import copy from pip._vendor import pkg_resources, requests @@ -18,8 +16,6 @@ DirectoryUrlHashUnsupported, HashUnpinned, InstallationError, PreviousBuildDirError, VcsHashUnsupported, ) -from pip._internal.index import FormatControl -from pip._internal.req.req_install import InstallRequirement from pip._internal.utils.hashes import MissingHashes from pip._internal.utils.logging import indent_log from pip._internal.utils.misc import ( @@ -51,18 +47,27 @@ def _install_build_reqs(finder, prefix, build_requirements): # NOTE: What follows is not a very good thing. # Eventually, this should move into the BuildEnvironment class and # that should handle all the isolation and sub-process invocation. - finder = copy(finder) - finder.format_control = FormatControl(set(), set([":all:"])) - urls = [ - finder.find_requirement( - InstallRequirement.from_line(r), upgrade=False).url - for r in build_requirements - ] args = [ sys.executable, '-m', 'pip', 'install', '--ignore-installed', '--no-user', '--prefix', prefix, - ] + list(urls) - + '--only-binary', ':all:', + ] + if finder.index_urls: + args.extend(['-i', finder.index_urls[0]]) + for extra_index in finder.index_urls[1:]: + args.extend(['--extra-index-url', extra_index]) + else: + args.append('--no-index') + for link in finder.find_links: + args.extend(['--find-links', link]) + for _, host, _ in finder.secure_origins: + args.extend(['--trusted-host', host]) + if finder.allow_all_prereleases: + args.append('--pre') + if finder.process_dependency_links: + args.append('--process-dependency-links') + args.append('--') + args.extend(build_requirements) with open_spinner("Installing build dependencies") as spinner: call_subprocess(args, show_stdout=False, spinner=spinner) diff --git a/tests/data/packages/pep518_with_extra_and_markers-1.0.tar.gz b/tests/data/packages/pep518_with_extra_and_markers-1.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..d333fddb228c77b2da6a3fe74d8e142557f5977a GIT binary patch literal 926 zcmV;P17Z9hiwFp(H1Jvi|72-%bT4paa5XVFUw3JAXkTS`baG)|VQyq!ZDDe2WpZ;Z zF)lDJbYXG;?V4><+CUJ;dE5IGSA2oa5XckIv86LktF2>2r`Gm`!(<{^;MzPjcTw~0 zdkF?gR1lR|r~7+Ba+|vZ*!}O_9)u9Kv^Ulz6JramL}XjG?^vE4{ep-qT0?DC9*rvL zsA_uDI<2{5PDL~Hj;R{DZgwiFuF6J*wkjnMb74o6R?b5PQ3QAPTXsGFAo=ly5H9uq z@xdo$zqfbvIRCd7_}|d9g8wz6-L6m-{l9h&LD-HhY~{Q3Hw*l2Dt%6Rwg=mEVQi4O z0VlC1?a4Mh?H%-ve)P!azyl?;M=&$(#9|yo#kK;T&D@#w3mbsX{~GoY_#k4T$exuO zk6l{~gUFj%D#&{Df4I}z-`hR;)?ogc^e?mhRR5Yx{Hm_YGt_?>Fn{324$v?Oqu?hD zL_-9gi)ups=lbU$;;=Coj@CB+t7f|}|LdC8LH(D(8H`32^M^s72zz9m$INwTmu3yQ zE&zG15=;mGvHlnKXvpwU((q|MY5mt}YgqriEdMVk6IZVP3>hw1|NSHNpOSiB$vm$} z&nsB}VgA2G{~`!27cRhUh%2$;`p+n={|wzQasBuF{zp-v{_m^*lcUqGA9hb}s(-ou zO;a!EUu&tj|5MKVKil0Si#;7Cq_9ae-5Iz(OM9%gSR|_l*L{aL5Q6W3KS(T>`M>xo zV;9V2sQ(qd@B7aGYH|HrXSJk{>apr|COyc7# zd+k^2vctrFIRM&W%_UF`i=j8;QoI}^Z)B+%%kQx^PAvbT#J%Ou?CT#GAj@=i~^6& zBuVpYsfCaY3Oh-%}&Mk`|sa$7~w)Eeb9NT9cWjMkd=4o4)Nqx3)0AYjr|1uJ72*9+Mlx#PR|s zcGGmY%u{r100!{f1#7ekK%S|mwOi3(B)XOT)&x`Fp&2`8?z_os9 z%2I`euguOzk_F^WX^)h2|ibYKD}3q2#7gXJLfcyi_?m|MJv`k+-l0fX8Dcp z#3}{xZRuC1PKS)Pi3{YI8*0!s$w=IRg*i^omgE=2=cJaU=IE7FlxUwjqkF>hDSD`V zyL)M0JTSEKfLIDwsD*pDy83XR_wYS?k=I*S>)e_1n}ZCl7(XcTKkKdQrE^k$Q;>(( zNgcgTefE`s7Yr^Kn_V!z@PzBsdHsuDb*}Mh=z5(!>9Z+FLsQH5DVL|u_8^TFCYR2h zKJR_i_sr^+P6=g~9cW2oaaH&K2B33J0kJGDXZgB@IJ!87IL7wwYHYwTd3<~3RgQ(t_Zwx{9B z-Mp38cDP*FE|Pb|=g=QCr-xl>+nvhDz@W&)z#xsw=|Qf}{y{FK7rpZr8;Gzzs9pL` z*oXJ&)uTFRlv~@Jm^d%w2(WON`6o_xs;@OwPAyxr{)_C~V$FBQw$*qB-$|af?9Yy( zE$3V!e@@;L8lNY0fLXcv<($iU!2wT>o|IZRJNe%94Jwa!=X9@`Xz}%D=fCEL1J3&n zOkuneez-fc)$M_dU*G$W!m0eX%>6#U(R^n*@AfUec<#zo9*+GwVn^e)>gJ1I;WC`^ z$*h3s&IbFn!bTT4Z7<}1Y2IoZV;57?sde0cj*-p%>nm8N&yN)rPH>-9<$CJ~n_tVL zHmQg<`57|X3;S|U7s+?}I@&7ymVfam;WqP)=}o(?9{DSE=uVGz=C%FypO2kh<@vbf ztX%BLO-jj<{x2@rXIOlVU%;B~IRD_pl4G|^moLlcQ9hdaHe7RMKYMM;z6HWZIyY@_ z+??oh`%~ODo9KW2^Iu=>dLwF5FsnG}N%i%!>}PlBxb9jti8Vo@=WlG(uJ5<+@BhaX z;LXS+!i>AP0!9%SG&F)J%)$#%mbGg=;okjYJ@oUZWMYZLm0)+ ZjKe5MmJ9G^WdkW@2SPret!r68JOF_(W}N^4 literal 0 HcmV?d00001 diff --git a/tests/data/src/pep518_with_extra_and_markers-1.0/MANIFEST.in b/tests/data/src/pep518_with_extra_and_markers-1.0/MANIFEST.in new file mode 100644 index 00000000000..bec201fc83b --- /dev/null +++ b/tests/data/src/pep518_with_extra_and_markers-1.0/MANIFEST.in @@ -0,0 +1 @@ +include pyproject.toml diff --git a/tests/data/src/pep518_with_extra_and_markers-1.0/pep518_with_extra_and_markers.py b/tests/data/src/pep518_with_extra_and_markers-1.0/pep518_with_extra_and_markers.py new file mode 100644 index 00000000000..7986d11379a --- /dev/null +++ b/tests/data/src/pep518_with_extra_and_markers-1.0/pep518_with_extra_and_markers.py @@ -0,0 +1 @@ +#dummy diff --git a/tests/data/src/pep518_with_extra_and_markers-1.0/pyproject.toml b/tests/data/src/pep518_with_extra_and_markers-1.0/pyproject.toml new file mode 100644 index 00000000000..c4b9b118f54 --- /dev/null +++ b/tests/data/src/pep518_with_extra_and_markers-1.0/pyproject.toml @@ -0,0 +1,7 @@ +[build-system] +requires=[ + "requires_simple_extra[extra]", + "simplewheel==1.0; python_version < '3'", + "simplewheel==2.0; python_version >= '3'", + "setuptools", "wheel", +] diff --git a/tests/data/src/pep518_with_extra_and_markers-1.0/setup.cfg b/tests/data/src/pep518_with_extra_and_markers-1.0/setup.cfg new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/data/src/pep518_with_extra_and_markers-1.0/setup.py b/tests/data/src/pep518_with_extra_and_markers-1.0/setup.py new file mode 100644 index 00000000000..29a8175e4d1 --- /dev/null +++ b/tests/data/src/pep518_with_extra_and_markers-1.0/setup.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +import sys + +from setuptools import setup + +# ensure dependencies are installed +import simple +import simplewheel + +assert simplewheel.__version__ == '1.0' if sys.version_info < (3,) else '2.0' + +setup(name='pep518_with_extra_and_markers', + version='1.0', + py_modules=['pep518_with_extra_and_markers'], + ) diff --git a/tests/functional/test_install.py b/tests/functional/test_install.py index e794b4ea87d..7926b939fbc 100644 --- a/tests/functional/test_install.py +++ b/tests/functional/test_install.py @@ -54,6 +54,19 @@ def test_pep518_with_user_pip(script, virtualenv, pip_src, ) +def test_pep518_with_extra_and_markers(script, data, common_wheels): + script.pip( + 'wheel', '--no-index', + '-f', common_wheels, + '-f', data.find_links, + # Add tests/data/packages4, which contains a wheel for + # simple==1.0 (needed by requires_simple_extra[extra]). + '-f', data.find_links4, + data.src.join("pep518_with_extra_and_markers-1.0"), + use_module=True, + ) + + @pytest.mark.network def test_pip_second_command_line_interface_works(script, data): """ diff --git a/tests/lib/__init__.py b/tests/lib/__init__.py index cf953606063..7f1dd5d0c0d 100644 --- a/tests/lib/__init__.py +++ b/tests/lib/__init__.py @@ -100,6 +100,10 @@ def packages2(self): def packages3(self): return self.root.join("packages3") + @property + def packages4(self): + return self.root.join("packages4") + @property def src(self): return self.root.join("src") @@ -124,6 +128,10 @@ def find_links2(self): def find_links3(self): return path_to_url(self.packages3) + @property + def find_links4(self): + return path_to_url(self.packages4) + def index_url(self, index="simple"): return path_to_url(self.root.join("indexes", index)) From 7b4790d0cade86c484fdcfbf94447cc032ffaa41 Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Thu, 19 Apr 2018 09:45:30 +0200 Subject: [PATCH 4/7] cleanup PEP 518 implementation - remove unused `BuildEnvironment` parameter: `no_clean` - move helper to install build requirement to the `BuildEnvironment` class - simplify a little the 2 different code paths (with and without build isolation) --- src/pip/_internal/build_env.py | 42 +++++++++++++++++----- src/pip/_internal/operations/prepare.py | 47 ++++--------------------- src/pip/_internal/req/req_install.py | 4 +-- 3 files changed, 42 insertions(+), 51 deletions(-) diff --git a/src/pip/_internal/build_env.py b/src/pip/_internal/build_env.py index 791d7346588..f4302203457 100644 --- a/src/pip/_internal/build_env.py +++ b/src/pip/_internal/build_env.py @@ -2,27 +2,28 @@ """ import os +import sys from distutils.sysconfig import get_python_lib from sysconfig import get_paths +from pip._internal.utils.misc import call_subprocess from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.ui import open_spinner class BuildEnvironment(object): """Creates and manages an isolated environment to install build deps """ - def __init__(self, no_clean): + def __init__(self): self._temp_dir = TempDirectory(kind="build-env") - self._no_clean = no_clean + self._temp_dir.create() @property def path(self): return self._temp_dir.path def __enter__(self): - self._temp_dir.create() - self.save_path = os.environ.get('PATH', None) self.save_pythonpath = os.environ.get('PYTHONPATH', None) self.save_nousersite = os.environ.get('PYTHONNOUSERSITE', None) @@ -58,9 +59,6 @@ def __enter__(self): return self.path def __exit__(self, exc_type, exc_val, exc_tb): - if not self._no_clean: - self._temp_dir.cleanup() - def restore_var(varname, old_value): if old_value is None: os.environ.pop(varname, None) @@ -74,12 +72,37 @@ def restore_var(varname, old_value): def cleanup(self): self._temp_dir.cleanup() + def install_requirements(self, finder, requirements, message): + args = [ + sys.executable, '-m', 'pip', 'install', '--ignore-installed', + '--no-user', '--prefix', self.path, + '--only-binary', ':all:', + ] + if finder.index_urls: + args.extend(['-i', finder.index_urls[0]]) + for extra_index in finder.index_urls[1:]: + args.extend(['--extra-index-url', extra_index]) + else: + args.append('--no-index') + for link in finder.find_links: + args.extend(['--find-links', link]) + for _, host, _ in finder.secure_origins: + args.extend(['--trusted-host', host]) + if finder.allow_all_prereleases: + args.append('--pre') + if finder.process_dependency_links: + args.append('--process-dependency-links') + args.append('--') + args.extend(requirements) + with open_spinner(message) as spinner: + call_subprocess(args, show_stdout=False, spinner=spinner) + class NoOpBuildEnvironment(BuildEnvironment): """A no-op drop-in replacement for BuildEnvironment """ - def __init__(self, no_clean): + def __init__(self): pass def __enter__(self): @@ -90,3 +113,6 @@ def __exit__(self, exc_type, exc_val, exc_tb): def cleanup(self): pass + + def install_requirements(self, finder, requirements, message): + raise NotImplementedError() diff --git a/src/pip/_internal/operations/prepare.py b/src/pip/_internal/operations/prepare.py index d2331b69e26..ff9b1e6a1df 100644 --- a/src/pip/_internal/operations/prepare.py +++ b/src/pip/_internal/operations/prepare.py @@ -3,11 +3,10 @@ import logging import os -import sys from pip._vendor import pkg_resources, requests -from pip._internal.build_env import NoOpBuildEnvironment +from pip._internal.build_env import BuildEnvironment from pip._internal.compat import expanduser from pip._internal.download import ( is_dir_url, is_file_url, is_vcs_url, unpack_url, url_to_path, @@ -18,10 +17,7 @@ ) from pip._internal.utils.hashes import MissingHashes from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import ( - call_subprocess, display_path, normalize_path, -) -from pip._internal.utils.ui import open_spinner +from pip._internal.utils.misc import display_path, normalize_path from pip._internal.vcs import vcs logger = logging.getLogger(__name__) @@ -43,35 +39,6 @@ def make_abstract_dist(req): return IsSDist(req) -def _install_build_reqs(finder, prefix, build_requirements): - # NOTE: What follows is not a very good thing. - # Eventually, this should move into the BuildEnvironment class and - # that should handle all the isolation and sub-process invocation. - args = [ - sys.executable, '-m', 'pip', 'install', '--ignore-installed', - '--no-user', '--prefix', prefix, - '--only-binary', ':all:', - ] - if finder.index_urls: - args.extend(['-i', finder.index_urls[0]]) - for extra_index in finder.index_urls[1:]: - args.extend(['--extra-index-url', extra_index]) - else: - args.append('--no-index') - for link in finder.find_links: - args.extend(['--find-links', link]) - for _, host, _ in finder.secure_origins: - args.extend(['--trusted-host', host]) - if finder.allow_all_prereleases: - args.append('--pre') - if finder.process_dependency_links: - args.append('--process-dependency-links') - args.append('--') - args.extend(build_requirements) - with open_spinner("Installing build dependencies") as spinner: - call_subprocess(args, show_stdout=False, spinner=spinner) - - class DistAbstraction(object): """Abstracts out the wheel vs non-wheel Resolver.resolve() logic. @@ -149,12 +116,10 @@ def format_reqs(rs): ) if should_isolate: - with self.req.build_env: - pass - _install_build_reqs(finder, self.req.build_env.path, - build_requirements) - else: - self.req.build_env = NoOpBuildEnvironment(no_clean=False) + self.req.build_env = BuildEnvironment() + self.req.build_env.install_requirements( + finder, build_requirements, + "Installing build dependencies") self.req.run_egg_info() self.req.assert_source_matches_version() diff --git a/src/pip/_internal/req/req_install.py b/src/pip/_internal/req/req_install.py index ddd167c66c0..f3515e40ce2 100644 --- a/src/pip/_internal/req/req_install.py +++ b/src/pip/_internal/req/req_install.py @@ -22,7 +22,7 @@ from pip._vendor.pkg_resources import RequirementParseError, parse_requirements from pip._internal import wheel -from pip._internal.build_env import BuildEnvironment +from pip._internal.build_env import NoOpBuildEnvironment from pip._internal.compat import native_str from pip._internal.download import ( is_archive_file, is_url, path_to_url, url_to_path, @@ -127,7 +127,7 @@ def __init__(self, req, comes_from, source_dir=None, editable=False, self.is_direct = False self.isolated = isolated - self.build_env = BuildEnvironment(no_clean=True) + self.build_env = NoOpBuildEnvironment() @classmethod def from_editable(cls, editable_req, comes_from=None, isolated=False, From 1ac5f0991133275f38c1d3f01e7283b3612b95e8 Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Thu, 19 Apr 2018 09:49:35 +0200 Subject: [PATCH 5/7] tweak output when installing PEP 518 build dependencies Suppress warnings about out-of-PATH script installs. --- src/pip/_internal/build_env.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pip/_internal/build_env.py b/src/pip/_internal/build_env.py index f4302203457..0dc6ab974bc 100644 --- a/src/pip/_internal/build_env.py +++ b/src/pip/_internal/build_env.py @@ -75,7 +75,7 @@ def cleanup(self): def install_requirements(self, finder, requirements, message): args = [ sys.executable, '-m', 'pip', 'install', '--ignore-installed', - '--no-user', '--prefix', self.path, + '--no-user', '--prefix', self.path, '--no-warn-script-location', '--only-binary', ':all:', ] if finder.index_urls: From 77f6ac676a012ca48d82f848b28b3a706b8cca4e Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Tue, 24 Apr 2018 11:14:23 +0200 Subject: [PATCH 6/7] forward verbose flag to build dependencies installs --- src/pip/_internal/build_env.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pip/_internal/build_env.py b/src/pip/_internal/build_env.py index 0dc6ab974bc..612b46352c2 100644 --- a/src/pip/_internal/build_env.py +++ b/src/pip/_internal/build_env.py @@ -1,6 +1,7 @@ """Build Environment used for isolation during sdist building """ +import logging import os import sys from distutils.sysconfig import get_python_lib @@ -11,6 +12,9 @@ from pip._internal.utils.ui import open_spinner +logger = logging.getLogger(__name__) + + class BuildEnvironment(object): """Creates and manages an isolated environment to install build deps """ @@ -78,6 +82,8 @@ def install_requirements(self, finder, requirements, message): '--no-user', '--prefix', self.path, '--no-warn-script-location', '--only-binary', ':all:', ] + if logger.getEffectiveLevel() <= logging.DEBUG: + args.append('-v') if finder.index_urls: args.extend(['-i', finder.index_urls[0]]) for extra_index in finder.index_urls[1:]: From 92e6e19e7a4c4b96bf4bbb88bda3fd4000f49a74 Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Tue, 24 Apr 2018 11:16:13 +0200 Subject: [PATCH 7/7] minor cleanup --- src/pip/_internal/wheel.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pip/_internal/wheel.py b/src/pip/_internal/wheel.py index 04552306539..4723bf7b7c3 100644 --- a/src/pip/_internal/wheel.py +++ b/src/pip/_internal/wheel.py @@ -24,7 +24,6 @@ from pip._vendor.six import StringIO from pip._internal import pep425tags -from pip._internal.build_env import BuildEnvironment from pip._internal.download import path_to_url, unpack_url from pip._internal.exceptions import ( InstallationError, InvalidWheelFilename, UnsupportedWheel,