1
1
from __future__ import annotations
2
2
3
3
from copy import deepcopy
4
+ from typing import Optional , Set , cast
4
5
5
- from packaging .markers import Variable # type: ignore[attr-defined]
6
+ from packaging .markers import Marker , Op , Value , Variable # type: ignore[attr-defined]
6
7
from packaging .requirements import Requirement
7
8
8
9
@@ -29,25 +30,42 @@ def dependencies_with_extras(deps: list[Requirement], extras: set[str], package_
29
30
30
31
31
32
def extract_extra_markers (deps : list [Requirement ]) -> list [tuple [Requirement , set [str | None ]]]:
32
- # extras might show up as markers, move them into extras property
33
- result : list [tuple [Requirement , set [str | None ]]] = []
34
- for req in deps :
35
- req = deepcopy (req )
36
- markers : list [str | tuple [Variable , Variable , Variable ]] = getattr (req .marker , "_markers" , []) or []
37
- _at : int | None = None
38
- extra_markers = set ()
39
- for _at , (marker_key , op , marker_value ) in (
40
- (_at_marker , marker )
41
- for _at_marker , marker in enumerate (markers )
42
- if isinstance (marker , tuple ) and len (marker ) == 3
43
- ):
44
- if marker_key .value == "extra" and op .value == "==" : # pragma: no branch
45
- extra_markers .add (marker_value .value )
46
- del markers [_at ]
47
- _at -= 1
48
- if _at >= 0 and (isinstance (markers [_at ], str ) and markers [_at ] in ("and" , "or" )):
49
- del markers [_at ]
50
- if len (markers ) == 0 :
51
- req .marker = None
52
- result .append ((req , extra_markers or {None }))
33
+ """
34
+ Extract extra markers from dependencies.
35
+
36
+ :param deps: the dependencies
37
+ :return: a list of requirement, extras set
38
+ """
39
+ result = [_extract_extra_markers (d ) for d in deps ]
53
40
return result
41
+
42
+
43
+ def _extract_extra_markers (req : Requirement ) -> tuple [Requirement , set [str | None ]]:
44
+ req = deepcopy (req )
45
+ markers : list [str | tuple [Variable , Op , Variable ]] = getattr (req .marker , "_markers" , []) or []
46
+ new_markers : list [str | tuple [Variable , Op , Variable ]] = []
47
+ extra_markers : set [str ] = set () # markers that have a key of extra
48
+ marker = markers .pop (0 ) if markers else None
49
+ while marker :
50
+ extra = _get_extra (marker )
51
+ if extra is not None :
52
+ extra_markers .add (extra )
53
+ if new_markers and new_markers [- 1 ] in ("and" , "or" ):
54
+ del new_markers [- 1 ]
55
+ marker = markers .pop (0 ) if markers else None
56
+ if marker in ("and" , "or" ):
57
+ marker = markers .pop (0 ) if markers else None
58
+ else :
59
+ new_markers .append (marker )
60
+ marker = markers .pop (0 ) if markers else None
61
+ if new_markers :
62
+ cast (Marker , req .marker )._markers = new_markers
63
+ else :
64
+ req .marker = None
65
+ return req , cast (Set [Optional [str ]], extra_markers ) or {None }
66
+
67
+
68
+ def _get_extra (_marker : str | tuple [Variable , Op , Value ]) -> str | None :
69
+ if isinstance (_marker , tuple ) and len (_marker ) == 3 and _marker [0 ].value == "extra" and _marker [1 ].value == "==" :
70
+ return cast (str , _marker [2 ].value )
71
+ return None
0 commit comments