@@ -240,8 +240,8 @@ def postprocess(self, testenv_config, value):
240
240
241
241
class InstallcmdOption :
242
242
name = "install_command"
243
- type = "argv "
244
- default = "python -m pip install {opts} {packages}"
243
+ type = "argv_install_command "
244
+ default = r "python -m pip install \ {opts\} \ {packages\ }"
245
245
help = "install command for dependencies and package under test."
246
246
247
247
def postprocess (self , testenv_config , value ):
@@ -1374,6 +1374,7 @@ def make_envconfig(self, name, section, subs, config, replace=True):
1374
1374
"dict_setenv" ,
1375
1375
"argv" ,
1376
1376
"argvlist" ,
1377
+ "argv_install_command" ,
1377
1378
):
1378
1379
meth = getattr (reader , "get{}" .format (atype ))
1379
1380
res = meth (env_attr .name , env_attr .default , replace = replace )
@@ -1558,7 +1559,15 @@ def __repr__(self):
1558
1559
1559
1560
1560
1561
class SectionReader :
1561
- def __init__ (self , section_name , cfgparser , fallbacksections = None , factors = (), prefix = None ):
1562
+ def __init__ (
1563
+ self ,
1564
+ section_name ,
1565
+ cfgparser ,
1566
+ fallbacksections = None ,
1567
+ factors = (),
1568
+ prefix = None ,
1569
+ posargs = "" ,
1570
+ ):
1562
1571
if prefix is None :
1563
1572
self .section_name = section_name
1564
1573
else :
@@ -1569,6 +1578,7 @@ def __init__(self, section_name, cfgparser, fallbacksections=None, factors=(), p
1569
1578
self ._subs = {}
1570
1579
self ._subststack = []
1571
1580
self ._setenv = None
1581
+ self .posargs = posargs
1572
1582
1573
1583
def get_environ_value (self , name ):
1574
1584
if self ._setenv is None :
@@ -1661,6 +1671,15 @@ def getargvlist(self, name, default="", replace=True):
1661
1671
def getargv (self , name , default = "" , replace = True ):
1662
1672
return self .getargvlist (name , default , replace = replace )[0 ]
1663
1673
1674
+ def getargv_install_command (self , name , default = "" , replace = True ):
1675
+ s = self .getstring (name , default , replace = False )
1676
+ if "{packages}" in s :
1677
+ s = s .replace ("{packages}" , r"\{packages\}" )
1678
+ if "{opts}" in s :
1679
+ s = s .replace ("{opts}" , r"\{opts\}" )
1680
+
1681
+ return _ArgvlistReader .getargvlist (self , s , replace = replace )[0 ]
1682
+
1664
1683
def getstring (self , name , default = None , replace = True , crossonly = False , no_fallback = False ):
1665
1684
x = None
1666
1685
sections = [self .section_name ] + ([] if no_fallback else self .fallbacksections )
@@ -1685,6 +1704,17 @@ def getstring(self, name, default=None, replace=True, crossonly=False, no_fallba
1685
1704
x = self ._replace_if_needed (x , name , replace , crossonly )
1686
1705
return x
1687
1706
1707
+ def getposargs (self , default = None ):
1708
+ if self .posargs :
1709
+ posargs = self .posargs
1710
+ if sys .platform .startswith ("win" ):
1711
+ posargs_string = list2cmdline ([x for x in posargs if x ])
1712
+ else :
1713
+ posargs_string = " " .join ([shlex_quote (x ) for x in posargs if x ])
1714
+ return posargs_string
1715
+ else :
1716
+ return default or ""
1717
+
1688
1718
def _replace_if_needed (self , x , name , replace , crossonly ):
1689
1719
if replace and x and hasattr (x , "replace" ):
1690
1720
x = self ._replace (x , name = name , crossonly = crossonly )
@@ -1771,11 +1801,8 @@ def _replace_match(self, match):
1771
1801
if not any (g .values ()):
1772
1802
return os .pathsep
1773
1803
1774
- # special case: opts and packages. Leave {opts} and
1775
- # {packages} intact, they are replaced manually in
1776
- # _venv.VirtualEnv.run_install_command.
1777
- if sub_value in ("opts" , "packages" ):
1778
- return "{{{}}}" .format (sub_value )
1804
+ if sub_value == "posargs" :
1805
+ return self .reader .getposargs (match .group ("default_value" ))
1779
1806
1780
1807
try :
1781
1808
sub_type = g ["sub_type" ]
@@ -1790,6 +1817,8 @@ def _replace_match(self, match):
1790
1817
if is_interactive ():
1791
1818
return match .group ("substitution_value" )
1792
1819
return match .group ("default_value" )
1820
+ if sub_type == "posargs" :
1821
+ return self .reader .getposargs (match .group ("substitution_value" ))
1793
1822
if sub_type is not None :
1794
1823
raise tox .exception .ConfigError (
1795
1824
"No support for the {} substitution type" .format (sub_type ),
@@ -1883,28 +1912,17 @@ def getargvlist(cls, reader, value, replace=True):
1883
1912
1884
1913
@classmethod
1885
1914
def processcommand (cls , reader , command , replace = True ):
1886
- posargs = getattr (reader , "posargs" , "" )
1887
- if sys .platform .startswith ("win" ):
1888
- posargs_string = list2cmdline ([x for x in posargs if x ])
1889
- else :
1890
- posargs_string = " " .join ([shlex_quote (x ) for x in posargs if x ])
1891
-
1892
1915
# Iterate through each word of the command substituting as
1893
1916
# appropriate to construct the new command string. This
1894
1917
# string is then broken up into exec argv components using
1895
1918
# shlex.
1896
1919
if replace :
1897
1920
newcommand = ""
1898
1921
for word in CommandParser (command ).words ():
1899
- if word == "{posargs}" or word == " []" :
1900
- newcommand += posargs_string
1922
+ if word == "[]" :
1923
+ newcommand += reader . getposargs ()
1901
1924
continue
1902
- elif word .startswith ("{posargs:" ) and word .endswith ("}" ):
1903
- if posargs :
1904
- newcommand += posargs_string
1905
- continue
1906
- else :
1907
- word = word [9 :- 1 ]
1925
+
1908
1926
new_arg = ""
1909
1927
new_word = reader ._replace (word )
1910
1928
new_word = reader ._replace (new_word )
0 commit comments