Skip to content

Commit

Permalink
add path to Distribution namedtuple
Browse files Browse the repository at this point in the history
  • Loading branch information
mabdinur committed Jun 9, 2022
1 parent 183e4ab commit 8feb275
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 23 deletions.
12 changes: 7 additions & 5 deletions ddtrace/internal/packages.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import typing


Distribution = typing.NamedTuple("Distribution", [("name", str), ("version", str)])
Distribution = typing.NamedTuple("Distribution", [("name", str), ("version", str), ("path", str)])

_DISTRIBUTIONS = None # type: typing.Optional[typing.Set[Distribution]]


def get_distributions():
# type: () -> typing.Set[Distribution]
"""returns the names, versions and path of all installed distributions"""
"""returns the name and version of all distributions in a python path"""
global _DISTRIBUTIONS
if _DISTRIBUTIONS is not None:
return _DISTRIBUTIONS
Expand All @@ -20,13 +20,15 @@ def get_distributions():

pkgs = set()
for dist in importlib_metadata.distributions():
# accessing dist.metadata reads all lines in the PKG-INFO and/or METADATA files
# We should avoid accessing dist.metadata more than once
# Get the root path of all files in a distribution
path = str(dist.locate_file(""))
# PKG-INFO and/or METADATA files are parsed when dist.metadata is accessed
# Optimization: we should avoid accessing dist.metadata more than once
metadata = dist.metadata
name = metadata["name"]
version = metadata["version"]
if name and version:
pkgs.add(Distribution(name, version))
pkgs.add(Distribution(path=path, name=name, version=version))

_DISTRIBUTIONS = pkgs
return _DISTRIBUTIONS
5 changes: 3 additions & 2 deletions ddtrace/internal/telemetry/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ def _get_application(key):

def get_dependencies():
# type: () -> List[Dict[str, str]]
"""Creates a list of dictionaries to store the name and version of all installed packages"""
return [{"name": dist.name, "version": dist.version} for dist in get_distributions()]
"""Returns a unique list of the names and versions of all installed packages"""
dependencies = {(dist.name, dist.version) for dist in get_distributions()}
return [{"name": name, "version": version} for name, version in dependencies]


def get_application(service, version, env):
Expand Down
21 changes: 14 additions & 7 deletions tests/internal/test_packages.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os

from ddtrace.internal.packages import get_distributions


Expand All @@ -7,13 +9,18 @@ def test_get_distributions():

pkg_resources_ws = {pkg.project_name for pkg in pkg_resources.working_set}

importlib_pkgs = {pkg.name for pkg in get_distributions()}
# The package name in typing_extensions-4.x.x.dist-info/METADATA is set to `typing_extensions`
# this is inconsistent with the package name found in pkg_resources. The block below corrects this.
# The correct package name is typing-extensions.
if "typing_extensions" in importlib_pkgs and "typing-extensions" in pkg_resources_ws:
importlib_pkgs.discard("typing_extensions")
importlib_pkgs.add("typing-extensions")
importlib_pkgs = set()
for pkg in get_distributions():
assert pkg.name
assert pkg.version
assert os.path.exists(pkg.path)
# The package name in typing_extensions-4.x.x.dist-info/METADATA is set to `typing_extensions`
# this is inconsistent with the package name found in pkg_resources. The block below corrects this.
# The correct package name is typing-extensions.
if pkg.name == "typing_extensions" and "typing-extensions" in pkg_resources_ws:
importlib_pkgs.add("typing-extensions")
else:
importlib_pkgs.add(pkg.name)

# assert that pkg_resources and importlib.metadata return the same packages
assert pkg_resources_ws == importlib_pkgs
12 changes: 3 additions & 9 deletions tests/tracer/telemetry/test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,6 @@ def test_get_container_id_when_container_does_not_exists():

def test_get_dependencies():
"""asserts that get_dependencies and get_distributions return the same packages"""
pkgs_as_dicts = get_dependencies()
pkgs_as_distributions = list(get_distributions())

assert len(pkgs_as_dicts) == len(pkgs_as_distributions)
for i in range(len(pkgs_as_dicts)):
pkg_dict = pkgs_as_dicts[i]
pkg_dist = pkgs_as_distributions[i]
assert pkg_dict["name"] == pkg_dist.name
assert pkg_dict["version"] == pkg_dist.version
pkgs_as_dicts = {(dep["name"], dep["version"]) for dep in get_dependencies()}
pkgs_as_distributions = {(dist.name, dist.version) for dist in get_distributions()}
assert pkgs_as_dicts == pkgs_as_distributions

0 comments on commit 8feb275

Please sign in to comment.