2020from packaging .requirements import InvalidRequirement , Requirement
2121
2222from opentelemetry .util ._importlib_metadata import (
23+ Distribution ,
2324 PackageNotFoundError ,
2425 version ,
2526)
2627
2728logger = getLogger (__name__ )
2829
30+ # TODO: consider replacing _either with _any or _or
31+
2932
3033class DependencyConflict :
3134 required : str | None = None
3235 found : str | None = None
33-
34- def __init__ (self , required : str | None , found : str | None = None ):
36+ # The following fields are used when an instrumentation requires any of a set of dependencies rather than all.
37+ required_either : Collection [str ] = []
38+ found_either : Collection [str ] = []
39+
40+ # TODO: No longer requires required field
41+ def __init__ (
42+ self ,
43+ required : str | None = None ,
44+ found : str | None = None ,
45+ required_either : Collection [str ] = [],
46+ found_either : Collection [str ] = [],
47+ ):
3548 self .required = required
3649 self .found = found
50+ # The following fields are used when an instrumentation requires any of a set of dependencies rather than all.
51+ self .required_either = required_either
52+ self .found_either = found_either
3753
3854 def __str__ (self ):
55+ if not self .required and (self .required_either or self .found_either ):
56+ print ("EITHER STRING" )
57+ # TODO: make sure this formats correctly
58+ return f'DependencyConflict: requested any of the following: "{ self .required_either } " but found: "{ self .found_either } "'
59+ print ("AND STRING" )
3960 return f'DependencyConflict: requested: "{ self .required } " but found: "{ self .found } "'
4061
4162
63+ # TODO: Figure out if this should be a subclass of DependencyConflict.
64+ # If now, change functions to return either and then ensure that all the dependents can handle the new value
65+ # class DependencyConflictEither(DependencyConflict):
66+ # required: Collection[str] = []
67+ # found: Collection[str] = []
68+
69+ # def __init__(self, required: Collection[str], found: Collection[str] = []):
70+ # self.required = required
71+ # self.found = found
72+
73+ # def __str__(self):
74+ # return f'DependencyConflictEither: requested: "{self.required}" but found: "{self.found}"'
75+
76+
4277class DependencyConflictError (Exception ):
4378 conflict : DependencyConflict
4479
@@ -49,14 +84,61 @@ def __str__(self):
4984 return str (self .conflict )
5085
5186
87+ def get_dist_dependency_conflicts (
88+ dist : Distribution ,
89+ ) -> DependencyConflict | None :
90+ instrumentation_deps = []
91+ instrumentation_either_deps = []
92+ extra = "extra"
93+ instruments = "instruments"
94+ instruments_marker = {extra : instruments }
95+ instruments_either = "instruments_either"
96+ instruments_either_marker = {extra : instruments_either }
97+ # print(f"dist: {dist}")
98+ # print(f"dist.requires: {dist.requires}")
99+ if dist .requires :
100+ for dep in dist .requires :
101+ print (f"dep: { dep } " )
102+ if extra not in dep :
103+ print (f"Skipping dep: { dep } " )
104+ continue
105+ if instruments not in dep and instruments_either not in dep :
106+ print (f"Skipping dep: { dep } " )
107+ continue
108+
109+ req = Requirement (dep )
110+ # print(f"req: {req}")
111+ if req .marker .evaluate (instruments_marker ): # type: ignore
112+ # print("Evaluated. Append")
113+ instrumentation_deps .append (req ) # type: ignore
114+ if req .marker .evaluate (instruments_either_marker ): # type: ignore
115+ # print("Evaluated. either. Append")
116+ # Need someway to separate
117+ instrumentation_either_deps .append (req ) # type: ignore
118+ dc = get_dependency_conflicts (
119+ instrumentation_deps , instrumentation_either_deps
120+ ) # type: ignore
121+ print (f"dep conf: { dc } " )
122+ return dc
123+ # return get_dependency_conflicts(instrumentation_deps, instrumentation_either_deps) # type: ignore
124+
125+
52126def get_dependency_conflicts (
53- deps : Collection [str | Requirement ],
127+ deps : Collection [
128+ str | Requirement
129+ ], # Depedencies all of which are required
130+ deps_either : Collection [
131+ str | Requirement
132+ ] = [], # Dependencies any of which are required
54133) -> DependencyConflict | None :
55134 for dep in deps :
135+ # TODO: what is this?
56136 if isinstance (dep , Requirement ):
137+ print ("REQUIREMENT" )
57138 req = dep
58139 else :
59140 try :
141+ print ("NOT REQUIREMENT" )
60142 req = Requirement (dep )
61143 except InvalidRequirement as exc :
62144 logger .warning (
@@ -69,8 +151,61 @@ def get_dependency_conflicts(
69151 try :
70152 dist_version = version (req .name )
71153 except PackageNotFoundError :
154+ # TODO: Technically this field should allow Requirements type. Tackle this in a separate PR.
72155 return DependencyConflict (dep )
73156
74157 if not req .specifier .contains (dist_version ):
158+ # TODO: Technically this field should allow Requirements type
75159 return DependencyConflict (dep , f"{ req .name } { dist_version } " )
160+
161+ # TODO: add eval of deps_either
162+ if deps_either :
163+ # TODO: change to using DependencyConflict
164+ is_dependency_conflict = True
165+ required_either : Collection [str ] = []
166+ found_either : Collection [str ] = []
167+ for dep in deps_either :
168+ # TODO: what is this?
169+ if isinstance (dep , Requirement ):
170+ print ("REQUIREMENT" )
171+ req = dep
172+ else :
173+ try :
174+ print ("NOT REQUIREMENT" )
175+ req = Requirement (dep )
176+ except InvalidRequirement as exc :
177+ logger .warning (
178+ 'error parsing dependency, reporting as a conflict: "%s" - %s' ,
179+ dep ,
180+ exc ,
181+ )
182+ return DependencyConflict (dep )
183+
184+ try :
185+ dist_version = version (req .name )
186+ except PackageNotFoundError :
187+ # print(f"PackageNotFoundError EITHER: {req.name}")
188+ # TODO: anything here?
189+ # return DependencyConflict(dep)
190+ required_either .append (str (dep ))
191+ continue
192+
193+ if req .specifier .contains (dist_version ):
194+ is_dependency_conflict = False
195+ # Since only one of the instrumentation_either dependencies is required, there is no depdendency conflict.
196+ break
197+ else :
198+ required_either .append (str (dep ))
199+ found_either .append (f"{ req .name } { dist_version } " )
200+
201+ if is_dependency_conflict :
202+ # return DependencyConflict(dep, f"{req.name} {dist_version}")
203+ # print (f"required_either: {required_either}")
204+ # print (f"found_either: {found_either}")
205+ return DependencyConflict (
206+ required_either = required_either ,
207+ found_either = found_either ,
208+ )
209+ return None
210+
76211 return None
0 commit comments