Skip to content

Commit 7d327e5

Browse files
committed
instruments-any
1 parent 3d6b9f2 commit 7d327e5

File tree

7 files changed

+64
-70
lines changed

7 files changed

+64
-70
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2323
([#3567](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3567))
2424
- `opentelemetry-resource-detector-containerid`: make it more quiet on platforms without cgroups
2525
([#3579](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3579))
26-
- `opentelemetry-instrumentation`: Fix dependency conflict detection when instrumented packages are not installed by moving check back to before instrumentors are loaded. Add "instruments_either" feature for instrumentations that target multiple packages.
26+
- `opentelemetry-instrumentation`: Fix dependency conflict detection when instrumented packages are not installed by moving check back to before instrumentors are loaded. Add "instruments-any" feature for instrumentations that target multiple packages.
2727
([#3610](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3610))
2828

2929
### Added

CONTRIBUTING.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -325,13 +325,13 @@ Below is a checklist of things to be mindful of when implementing a new instrume
325325
### Update supported instrumentation package versions
326326

327327
- Navigate to the **instrumentation package directory:**
328-
- Update **`pyproject.toml`** file by modifying _instruments_ or _instruments_either_ entry in the `[project.optional-dependencies]` section with the new version constraint
329-
- Update `_instruments` or `_instruments-either` variable in instrumentation **`package.py`** file with the new version constraint
328+
- Update **`pyproject.toml`** file by modifying _instruments_ or _instruments-any_ entry in the `[project.optional-dependencies]` section with the new version constraint
329+
- Update `_instruments` or `_instruments-any` variable in instrumentation **`package.py`** file with the new version constraint
330330
- At the **root of the project directory**, run `tox -e generate` to regenerate necessary files
331331

332-
Please note that _instruments_either_ is an optional field that can be used instead of or in addition to _instruments_. While _instruments_ is a list of dependencies, _all_ of which are expected by the instrumentation, _instruments_either_ is a list _any_ of which but not all are expected.
332+
Please note that _instruments-any_ is an optional field that can be used instead of or in addition to _instruments_. While _instruments_ is a list of dependencies, _all_ of which are expected by the instrumentation, _instruments-any_ is a list _any_ of which but not all are expected.
333333

334-
<!-- See https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3610 for details on instruments_either -->
334+
<!-- See https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3610 for details on instruments-any -->
335335

336336
If you're adding support for a new version of the instrumentation package, follow these additional steps:
337337

opentelemetry-instrumentation/src/opentelemetry/instrumentation/dependencies.py

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -40,33 +40,33 @@ class DependencyConflict:
4040
Attributes:
4141
required: The required dependency specification that conflicts with what's installed.
4242
found: The actual dependency that was found installed (if any).
43-
required_either: Collection of dependency specifications where any one would satisfy
43+
required_any: Collection of dependency specifications where any one would satisfy
4444
the requirement (for either/or scenarios).
45-
found_either: Collection of actual dependencies found for either/or scenarios.
45+
found_any: Collection of actual dependencies found for either/or scenarios.
4646
"""
4747

4848
required: str | None = None
4949
found: str | None = None
5050
# The following fields are used when an instrumentation requires any of a set of dependencies rather than all.
51-
required_either: Collection[str] = None
52-
found_either: Collection[str] = None
51+
required_any: Collection[str] = None
52+
found_any: Collection[str] = None
5353

5454
def __init__(
5555
self,
5656
required: str | None = None,
5757
found: str | None = None,
58-
required_either: Collection[str] = None,
59-
found_either: Collection[str] = None,
58+
required_any: Collection[str] = None,
59+
found_any: Collection[str] = None,
6060
):
6161
self.required = required
6262
self.found = found
6363
# The following fields are used when an instrumentation requires any of a set of dependencies rather than all.
64-
self.required_either = required_either
65-
self.found_either = found_either
64+
self.required_any = required_any
65+
self.found_any = found_any
6666

6767
def __str__(self):
68-
if not self.required and (self.required_either or self.found_either):
69-
return f'DependencyConflict: requested any of the following: "{self.required_either}" but found: "{self.found_either}"'
68+
if not self.required and (self.required_any or self.found_any):
69+
return f'DependencyConflict: requested any of the following: "{self.required_any}" but found: "{self.found_any}"'
7070
return f'DependencyConflict: requested: "{self.required}" but found: "{self.found}"'
7171

7272

@@ -84,34 +84,34 @@ def get_dist_dependency_conflicts(
8484
dist: Distribution,
8585
) -> DependencyConflict | None:
8686
instrumentation_deps = []
87-
instrumentation_either_deps = []
87+
instrumentation_any_deps = []
8888
extra = "extra"
8989
instruments = "instruments"
9090
instruments_marker = {extra: instruments}
91-
instruments_either = "instruments_either"
92-
instruments_either_marker = {extra: instruments_either}
91+
instruments_any = "instruments-any"
92+
instruments_any_marker = {extra: instruments_any}
9393
if dist.requires:
9494
for dep in dist.requires:
9595
if extra not in dep:
9696
continue
97-
if instruments not in dep and instruments_either not in dep:
97+
if instruments not in dep and instruments_any not in dep:
9898
continue
9999

100100
req = Requirement(dep)
101101
if req.marker.evaluate(instruments_marker): # type: ignore
102102
instrumentation_deps.append(req) # type: ignore
103-
if req.marker.evaluate(instruments_either_marker): # type: ignore
104-
instrumentation_either_deps.append(req) # type: ignore
103+
if req.marker.evaluate(instruments_any_marker): # type: ignore
104+
instrumentation_any_deps.append(req) # type: ignore
105105
return get_dependency_conflicts(
106-
instrumentation_deps, instrumentation_either_deps
106+
instrumentation_deps, instrumentation_any_deps
107107
) # type: ignore
108108

109109

110110
def get_dependency_conflicts(
111111
deps: Collection[
112112
str | Requirement
113113
], # Dependencies all of which are required
114-
deps_either: Collection[
114+
deps_any: Collection[
115115
str | Requirement
116116
] = None, # Dependencies any of which are required
117117
) -> DependencyConflict | None:
@@ -137,22 +137,22 @@ def get_dependency_conflicts(
137137
if not req.specifier.contains(dist_version):
138138
return DependencyConflict(dep, f"{req.name} {dist_version}")
139139

140-
# If all the dependencies in "instruments" are present, check "instruments_either" for conflicts.
141-
if deps_either:
142-
return _get_dependency_conflicts_either(deps_either)
140+
# If all the dependencies in "instruments" are present, check "instruments-any" for conflicts.
141+
if deps_any:
142+
return _get_dependency_conflicts_any(deps_any)
143143
return None
144144

145145

146146
# This is a helper functions designed to ease reading and meet linting requirements.
147-
def _get_dependency_conflicts_either(
148-
deps_either: Collection[str | Requirement],
147+
def _get_dependency_conflicts_any(
148+
deps_any: Collection[str | Requirement],
149149
) -> DependencyConflict | None:
150-
if not deps_either:
150+
if not deps_any:
151151
return None
152152
is_dependency_conflict = True
153-
required_either: Collection[str] = []
154-
found_either: Collection[str] = []
155-
for dep in deps_either:
153+
required_any: Collection[str] = []
154+
found_any: Collection[str] = []
155+
for dep in deps_any:
156156
if isinstance(dep, Requirement):
157157
req = dep
158158
else:
@@ -169,20 +169,20 @@ def _get_dependency_conflicts_either(
169169
try:
170170
dist_version = version(req.name)
171171
except PackageNotFoundError:
172-
required_either.append(str(dep))
172+
required_any.append(str(dep))
173173
continue
174174

175175
if req.specifier.contains(dist_version):
176-
# Since only one of the instrumentation_either dependencies is required, there is no dependency conflict.
176+
# Since only one of the instrumentation_any dependencies is required, there is no dependency conflict.
177177
is_dependency_conflict = False
178178
break
179179
# If the version does not match, add it to the list of unfulfilled requirement options.
180-
required_either.append(str(dep))
181-
found_either.append(f"{req.name} {dist_version}")
180+
required_any.append(str(dep))
181+
found_any.append(f"{req.name} {dist_version}")
182182

183183
if is_dependency_conflict:
184184
return DependencyConflict(
185-
required_either=required_either,
186-
found_either=found_either,
185+
required_any=required_any,
186+
found_any=found_any,
187187
)
188188
return None

opentelemetry-instrumentation/tests/test_dependencies.py

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ def requires(self):
110110
self.assertTrue(conflict is None)
111111

112112
@patch("opentelemetry.instrumentation.dependencies.version")
113-
def test_get_dist_dependency_conflicts_either(self, version_mock):
113+
def test_get_dist_dependency_conflicts_any(self, version_mock):
114114
class MockDistribution(Distribution):
115115
def locate_file(self, path):
116116
pass
@@ -121,8 +121,8 @@ def read_text(self, filename):
121121
@property
122122
def requires(self):
123123
return [
124-
'foo ~= 1.0; extra == "instruments_either"',
125-
'bar ~= 1.0; extra == "instruments_either"',
124+
'foo ~= 1.0; extra == "instruments-any"',
125+
'bar ~= 1.0; extra == "instruments-any"',
126126
]
127127

128128
dist = MockDistribution()
@@ -150,8 +150,8 @@ def read_text(self, filename):
150150
@property
151151
def requires(self):
152152
return [
153-
'foo ~= 1.0; extra == "instruments_either"',
154-
'bar ~= 1.0; extra == "instruments_either"',
153+
'foo ~= 1.0; extra == "instruments-any"',
154+
'bar ~= 1.0; extra == "instruments-any"',
155155
]
156156

157157
dist = MockDistribution()
@@ -163,12 +163,12 @@ def requires(self):
163163
self.assertTrue(isinstance(conflict, DependencyConflict))
164164
self.assertEqual(
165165
str(conflict),
166-
'''DependencyConflict: requested any of the following: "['foo~=1.0; extra == "instruments-either"', 'bar~=1.0; extra == "instruments-either"']" but found: "[]"''',
166+
'''DependencyConflict: requested any of the following: "['foo~=1.0; extra == "instruments-any"', 'bar~=1.0; extra == "instruments-any"']" but found: "[]"''',
167167
)
168168

169169
# Tests when both "and" and "either" dependencies are specified and both pass.
170170
@patch("opentelemetry.instrumentation.dependencies.version")
171-
def test_get_dist_dependency_conflicts_either_and(self, version_mock):
171+
def test_get_dist_dependency_conflicts_any_and(self, version_mock):
172172
class MockDistribution(Distribution):
173173
def locate_file(self, path):
174174
pass
@@ -181,8 +181,8 @@ def requires(self):
181181
# This indicates the instrumentation requires (foo and (bar or baz)))
182182
return [
183183
'foo ~= 1.0; extra == "instruments"',
184-
'bar ~= 2.0; extra == "instruments_either"',
185-
'baz ~= 3.0; extra == "instruments_either"',
184+
'bar ~= 2.0; extra == "instruments-any"',
185+
'baz ~= 3.0; extra == "instruments-any"',
186186
]
187187

188188
dist = MockDistribution()
@@ -202,9 +202,7 @@ def version_side_effect(package_name):
202202

203203
# Tests when both "and" and "either" dependencies are specified but the "and" dependencies fail to resolve.
204204
@patch("opentelemetry.instrumentation.dependencies.version")
205-
def test_get_dist_dependency_conflicts_either_and_failed(
206-
self, version_mock
207-
):
205+
def test_get_dist_dependency_conflicts_any_and_failed(self, version_mock):
208206
class MockDistribution(Distribution):
209207
def locate_file(self, path):
210208
pass
@@ -217,8 +215,8 @@ def requires(self):
217215
# This indicates the instrumentation requires (foo and (bar or baz)))
218216
return [
219217
'foo ~= 1.0; extra == "instruments"',
220-
'bar ~= 2.0; extra == "instruments_either"',
221-
'baz ~= 3.0; extra == "instruments_either"',
218+
'bar ~= 2.0; extra == "instruments-any"',
219+
'baz ~= 3.0; extra == "instruments-any"',
222220
]
223221

224222
dist = MockDistribution()
@@ -243,9 +241,7 @@ def version_side_effect(package_name):
243241

244242
# Tests when both "and" and "either" dependencies are specified but the "either" dependencies fail to resolve.
245243
@patch("opentelemetry.instrumentation.dependencies.version")
246-
def test_get_dist_dependency_conflicts_and_either_failed(
247-
self, version_mock
248-
):
244+
def test_get_dist_dependency_conflicts_and_any_failed(self, version_mock):
249245
class MockDistribution(Distribution):
250246
def locate_file(self, path):
251247
pass
@@ -258,8 +254,8 @@ def requires(self):
258254
# This indicates the instrumentation requires (foo and (bar or baz)))
259255
return [
260256
'foo ~= 1.0; extra == "instruments"',
261-
'bar ~= 2.0; extra == "instruments_either"',
262-
'baz ~= 3.0; extra == "instruments_either"',
257+
'bar ~= 2.0; extra == "instruments-any"',
258+
'baz ~= 3.0; extra == "instruments-any"',
263259
]
264260

265261
dist = MockDistribution()
@@ -279,5 +275,5 @@ def version_side_effect(package_name):
279275
self.assertTrue(isinstance(conflict, DependencyConflict))
280276
self.assertEqual(
281277
str(conflict),
282-
'''DependencyConflict: requested any of the following: "['bar~=2.0; extra == "instruments-either"', 'baz~=3.0; extra == "instruments-either"']" but found: "[]"''',
278+
'''DependencyConflict: requested any of the following: "['bar~=2.0; extra == "instruments-any"', 'baz~=3.0; extra == "instruments-any"']" but found: "[]"''',
283279
)

scripts/generate_instrumentation_bootstrap.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def main():
8484
pkg_name = pkg.get("name")
8585
if pkg_name in packages_to_exclude:
8686
continue
87-
if not pkg["instruments"] and not pkg["instruments_either"]:
87+
if not pkg["instruments"] and not pkg["instruments-any"]:
8888
default_instrumentations.elts.append(ast.Str(pkg["requirement"]))
8989
for target_pkg in pkg["instruments"]:
9090
libraries.elts.append(
@@ -93,8 +93,8 @@ def main():
9393
values=[ast.Str(target_pkg), ast.Str(pkg["requirement"])],
9494
)
9595
)
96-
# _instruments_either is an optional field that can be used instead of or in addition to _instruments. While _instruments is a list of dependencies, all of which are expected by the instrumentation, _instruments_either is a list any of which but not all are expected.
97-
for target_pkg in pkg["instruments_either"]:
96+
# _instruments-any is an optional field that can be used instead of or in addition to _instruments. While _instruments is a list of dependencies, all of which are expected by the instrumentation, _instruments-any is a list any of which but not all are expected.
97+
for target_pkg in pkg["instruments-any"]:
9898
libraries.elts.append(
9999
ast.Dict(
100100
keys=[ast.Str("library"), ast.Str("instrumentation")],

scripts/generate_instrumentation_readme.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,15 @@ def main(base_instrumentation_path):
5959
exec(fh.read(), pkg_info)
6060

6161
instruments_and = pkg_info.get("_instruments", ())
62-
# _instruments_either is an optional field that can be used instead of or in addition to _instruments. While _instruments is a list of dependencies, all of which are expected by the instrumentation, _instruments_either is a list any of which but not all are expected.
63-
instruments_either = pkg_info.get("_instruments_either", ())
62+
# _instruments-any is an optional field that can be used instead of or in addition to _instruments. While _instruments is a list of dependencies, all of which are expected by the instrumentation, _instruments-any is a list any of which but not all are expected.
63+
instruments_any = pkg_info.get("_instruments-any", ())
6464
supports_metrics = pkg_info.get("_supports_metrics")
6565
semconv_status = pkg_info.get("_semconv_status")
6666
instruments_all = ()
67-
if not instruments_and and not instruments_either:
67+
if not instruments_and and not instruments_any:
6868
instruments_all = (name,)
6969
else:
70-
instruments_all = tuple(instruments_and + instruments_either)
70+
instruments_all = tuple(instruments_and + instruments_any)
7171

7272
if not semconv_status:
7373
semconv_status = "development"

scripts/otel_packaging.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,13 @@ def get_instrumentation_packages(
6464
"optional-dependencies"
6565
]
6666
instruments = optional_dependencies.get("instruments", [])
67-
# _instruments_either is an optional field that can be used instead of or in addition to _instruments. While _instruments is a list of dependencies, all of which are expected by the instrumentation, _instruments_either is a list any of which but not all are expected.
68-
instruments_either = optional_dependencies.get(
69-
"instruments_either", []
70-
)
67+
# _instruments-any is an optional field that can be used instead of or in addition to _instruments. While _instruments is a list of dependencies, all of which are expected by the instrumentation, _instruments-any is a list any of which but not all are expected.
68+
instruments_any = optional_dependencies.get("instruments-any", [])
7169
instrumentation = {
7270
"name": pyproject_toml["project"]["name"],
7371
"version": version.strip(),
7472
"instruments": instruments,
75-
"instruments_either": instruments_either,
73+
"instruments-any": instruments_any,
7674
}
7775
if instrumentation["name"] in independent_packages:
7876
specifier = independent_packages[instrumentation["name"]]

0 commit comments

Comments
 (0)