diff --git a/.gitignore b/.gitignore index c587c52bfe9..b4a5c1bf459 100644 --- a/.gitignore +++ b/.gitignore @@ -152,9 +152,6 @@ CLAUDE.local.md .riot/venv* .riot/requirements/*.in -# Auto-generated version file -ddtrace/_version.py - # Benchmarks artifacts/ diff --git a/.gitlab/package.yml b/.gitlab/package.yml index e1740dc5858..f988bc88d71 100644 --- a/.gitlab/package.yml +++ b/.gitlab/package.yml @@ -1,33 +1,3 @@ -compute_library_version: - image: registry.ddbuild.io/images/dd-octo-sts-ci-base:2025.06-1 - tags: [ "arch:amd64" ] - stage: package - id_tokens: - DDOCTOSTS_ID_TOKEN: - aud: dd-octo-sts - script: | - set -eo pipefail - - if [ -z ${GH_TOKEN} ] - then - # Use dd-octo-sts to get GitHub token - dd-octo-sts token --scope DataDog/dd-trace-py --policy gitlab.github-access.read > token - gh auth login --with-token < token - rm token - fi - # Prevent git operation errors: - # failed to determine base repo: failed to run git: fatal: detected dubious ownership in repository at ... - git config --global --add safe.directory "${CI_PROJECT_DIR}" - .gitlab/download-library-version-from-gh-actions.sh - - echo "SETUPTOOLS_SCM_PRETEND_VERSION_FOR_DDTRACE=$(cat library-version/version.txt)" | tee library_version.env - echo "DDTRACE_VERSION=$(cat library-version/version.txt)" | tee -a library_version.env - artifacts: - reports: - dotenv: library_version.env - paths: - - "library-version/version.txt" - download_ddtrace_artifacts: image: registry.ddbuild.io/images/dd-octo-sts-ci-base:2025.06-1 tags: [ "arch:amd64" ] @@ -90,8 +60,6 @@ publish-wheels-to-s3: needs: - job: download_ddtrace_artifacts artifacts: true - - job: compute_library_version - artifacts: true variables: BUCKET: dd-trace-py-builds script: @@ -107,24 +75,20 @@ publish-wheels-to-s3: - printf ' - %s\n' "${WHEELS[@]}" - | - if [ -f library-version/version.txt ]; then - VERSION="$(tr -d '\r\n' < library-version/version.txt)" - fi + VERSION=$(grep '^version = ' pyproject.toml | head -1 | sed -E 's/version = "(.+)"/\1/') if [ -z "${VERSION:-}" ]; then - echo "ERROR: VERSION is not defined or library-version/version.txt missing!" + echo "ERROR: VERSION is not defined in pyproject.toml!" exit 1 fi - printf 'Detected version %s\n' ${VERSION} - # Upload all wheels to versioned prefix and pipeline-id prefix - - aws s3 cp --recursive --exclude "*" --include "*.whl" pywheels "s3://${BUCKET}/${VERSION}/" + # Upload all wheels to pipeline-id prefix - aws s3 cp --recursive --exclude "*" --include "*.whl" pywheels "s3://${BUCKET}/${CI_PIPELINE_ID}/" - | VERSION_ENC="${VERSION//+/%2B}" - S3_BASE_VER="https://${BUCKET}.s3.amazonaws.com/${VERSION_ENC}" S3_BASE_PIPE="https://${BUCKET}.s3.amazonaws.com/${CI_PIPELINE_ID}" generate_index_html() { @@ -141,15 +105,27 @@ publish-wheels-to-s3: } # Generate both minimal indexes - generate_index_html "index.version.html" generate_index_html "index.pipeline.html" # Upload to each S3 prefix - aws s3 cp "index.version.html" "s3://${BUCKET}/${VERSION}/index.html" --content-type text/html aws s3 cp "index.pipeline.html" "s3://${BUCKET}/${CI_PIPELINE_ID}/index.html" --content-type text/html # Print the clickable URLs - VER_INDEX_URL="${S3_BASE_VER}/index.html" PIPE_INDEX_URL="${S3_BASE_PIPE}/index.html" - echo "S3 index (version): ${VER_INDEX_URL}" echo "S3 index (pipeline): ${PIPE_INDEX_URL}" + + +# Fail if the downloaded package versions do not match the git tag version +verify_package_version: + image: registry.ddbuild.io/images/mirror/python:3.14.0 + tags: [ "arch:amd64" ] + stage: package + needs: [ download_ddtrace_artifacts ] + only: + # v2.10.0 + # v2.10.1 + # v2.10.0rc0 + # v2.10.0rc5 + - /^v[0-9]+\.[0-9]+\.[0-9]+(rc[0-9]+)?$/ + script: + - .gitlab/verify-package-versions.sh diff --git a/.gitlab/verify-package-versions.sh b/.gitlab/verify-package-versions.sh new file mode 100755 index 00000000000..9412ea5cc65 --- /dev/null +++ b/.gitlab/verify-package-versions.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail + +WHEEL_FILES=(pywheels/*.whl) +if [ ${#WHEEL_FILES[@]} -eq 0 ]; then + echo "No wheels found in pywheels/"; exit 1 +fi + +VERSION_TAG="${CI_COMMIT_TAG#v}" +echo "Verifying package version ${VERSION_TAG}" + +for wf in "${WHEEL_FILES[@]}"; do + echo "Checking wheel file: ${wf}" + WHEEL_VERSION=$(basename "${wf}" | awk -F '-' '{print $2}') + if [ "${WHEEL_VERSION}" != "${VERSION_TAG}" ]; then + echo "ERROR: Wheel version ${WHEEL_VERSION} does not match tag version ${VERSION_TAG}" + exit 1 + fi +done + +SDIST_FILES=(pywheels/*.tar.gz) +if [ ${#SDIST_FILES[@]} -eq 0 ]; then + echo "No sdist files found in pywheels/"; exit 1 +fi +for sf in "${SDIST_FILES[@]}"; do + echo "Checking sdist file: ${sf}" + SDIST_VERSION=$(basename "${sf}" | awk -F '-' '{print $2}' | sed 's/\.tar\.gz$//') + if [ "${SDIST_VERSION}" != "${VERSION_TAG}" ]; then + echo "ERROR: Sdist version ${SDIST_VERSION} does not match tag version ${VERSION_TAG}" + exit 1 + fi +done diff --git a/.sg/rules/ddtrace-version-import.yml b/.sg/rules/ddtrace-version-import.yml new file mode 100644 index 00000000000..5c3b53d851b --- /dev/null +++ b/.sg/rules/ddtrace-version-import.yml @@ -0,0 +1,50 @@ +id: ddtrace-version-import +message: Import `__version__` from `ddtrace.version` instead of `ddtrace` +severity: error +language: python +ignores: + - "tests/**" + - "benchmarks/**" +rule: + any: + # Match: from ddtrace import __version__ (using variable with constraint) + - pattern: from $MOD import __version__ + # Match: from ddtrace import __version__ as $ALIAS + - pattern: from $MOD import __version__ as $ALIAS + # Match: from ddtrace import $$$IMPORTS, __version__ + - pattern: from $MOD import $$$IMPORTS, __version__ + # Match: from ddtrace import $$$IMPORTS, __version__ as $ALIAS + - pattern: from $MOD import $$$IMPORTS, __version__ as $ALIAS + # Match: from ddtrace import __version__, $$$IMPORTS + - pattern: from $MOD import __version__, $$$IMPORTS + # Match: from ddtrace import __version__ as $ALIAS, $$$IMPORTS + - pattern: from $MOD import __version__ as $ALIAS, $$$IMPORTS + # Match: from ddtrace import $$$IMPORTS, __version__, $$$IMPORTS (middle case) + - pattern: from $MOD import $$$IMPORTS, __version__, $$$IMPORTS + # Match: from ddtrace import $$$IMPORTS, __version__ as $ALIAS, $$$IMPORTS (middle case with alias) + - pattern: from $MOD import $$$IMPORTS, __version__ as $ALIAS, $$$IMPORTS + # Match: ddtrace.__version__ usage + - pattern: ddtrace.__version__ +constraints: + MOD: + regex: "^ddtrace$" + ALIAS: + regex: ".*" +note: | + The `__version__` attribute should be imported from `ddtrace.version` to avoid circular dependencies and ensure proper version management. + + Change your imports as follows: + + **Before:** + ```python + from ddtrace import __version__ + import ddtrace + version = ddtrace.__version__ + ``` + + **After:** + ```python + from ddtrace.version import __version__ + ``` + + This ensures that `__version__` is accessed from the dedicated version module, preventing circular import issues and making version management more explicit. diff --git a/.sg/tests/__snapshots__/ddtrace-version-import-snapshot.yml b/.sg/tests/__snapshots__/ddtrace-version-import-snapshot.yml new file mode 100644 index 00000000000..994b6bf7d40 --- /dev/null +++ b/.sg/tests/__snapshots__/ddtrace-version-import-snapshot.yml @@ -0,0 +1,226 @@ +id: ddtrace-version-import +snapshots: + ddtrace.__version__: + labels: + - source: ddtrace.__version__ + style: primary + start: 0 + end: 19 + from ddtrace import __version__: + labels: + - source: from ddtrace import __version__ + style: primary + start: 0 + end: 31 + from ddtrace import __version__ as V: + labels: + - source: from ddtrace import __version__ as V + style: primary + start: 0 + end: 36 + from ddtrace import __version__ as V, config, tracer: + labels: + - source: from ddtrace import __version__ as V, config, tracer + style: primary + start: 0 + end: 52 + from ddtrace import __version__ as VERSION: + labels: + - source: from ddtrace import __version__ as VERSION + style: primary + start: 0 + end: 42 + from ddtrace import __version__ as VERSION, tracer: + labels: + - source: from ddtrace import __version__ as VERSION, tracer + style: primary + start: 0 + end: 50 + from ddtrace import __version__ as VERSION, tracer, config, pin: + labels: + - source: from ddtrace import __version__ as VERSION, tracer, config, pin + style: primary + start: 0 + end: 63 + from ddtrace import __version__, config: + labels: + - source: from ddtrace import __version__, config + style: primary + start: 0 + end: 39 + from ddtrace import __version__, config, tracer: + labels: + - source: from ddtrace import __version__, config, tracer + style: primary + start: 0 + end: 47 + from ddtrace import __version__, tracer: + labels: + - source: from ddtrace import __version__, tracer + style: primary + start: 0 + end: 39 + from ddtrace import __version__, tracer, config, pin: + labels: + - source: from ddtrace import __version__, tracer, config, pin + style: primary + start: 0 + end: 52 + from ddtrace import config, __version__: + labels: + - source: from ddtrace import config, __version__ + style: primary + start: 0 + end: 39 + from ddtrace import config, __version__ as V: + labels: + - source: from ddtrace import config, __version__ as V + style: primary + start: 0 + end: 44 + from ddtrace import config, __version__ as V, tracer, pin: + labels: + - source: from ddtrace import config, __version__ as V, tracer, pin + style: primary + start: 0 + end: 57 + from ddtrace import config, __version__ as VERSION, tracer: + labels: + - source: from ddtrace import config, __version__ as VERSION, tracer + style: primary + start: 0 + end: 58 + from ddtrace import config, __version__, tracer: + labels: + - source: from ddtrace import config, __version__, tracer + style: primary + start: 0 + end: 47 + from ddtrace import config, __version__, tracer, pin: + labels: + - source: from ddtrace import config, __version__, tracer, pin + style: primary + start: 0 + end: 52 + from ddtrace import config, tracer, __version__: + labels: + - source: from ddtrace import config, tracer, __version__ + style: primary + start: 0 + end: 47 + from ddtrace import config, tracer, __version__ as VERSION: + labels: + - source: from ddtrace import config, tracer, __version__ as VERSION + style: primary + start: 0 + end: 58 + from ddtrace import config, tracer, pin, __version__: + labels: + - source: from ddtrace import config, tracer, pin, __version__ + style: primary + start: 0 + end: 52 + from ddtrace import config, tracer, pin, __version__ as V: + labels: + - source: from ddtrace import config, tracer, pin, __version__ as V + style: primary + start: 0 + end: 57 + ? |- + from ddtrace import tracer + version = ddtrace.__version__ + : labels: + - source: ddtrace.__version__ + style: primary + start: 37 + end: 56 + ? | + from ddtrace import tracer + version = ddtrace.__version__ + : labels: + - source: ddtrace.__version__ + style: primary + start: 37 + end: 56 + from ddtrace import tracer, __version__: + labels: + - source: from ddtrace import tracer, __version__ + style: primary + start: 0 + end: 39 + from ddtrace import tracer, __version__ as VERSION: + labels: + - source: from ddtrace import tracer, __version__ as VERSION + style: primary + start: 0 + end: 50 + from ddtrace import tracer, config, __version__ as VERSION, pin, span: + labels: + - source: from ddtrace import tracer, config, __version__ as VERSION, pin, span + style: primary + start: 0 + end: 69 + from ddtrace import tracer, config, __version__, pin, span: + labels: + - source: from ddtrace import tracer, config, __version__, pin, span + style: primary + start: 0 + end: 58 + ? | + import ddtrace + compare = ddtrace.__version__ > "1.0" + : labels: + - source: ddtrace.__version__ + style: primary + start: 25 + end: 44 + ? | + import ddtrace + config = {"version": ddtrace.__version__} + : labels: + - source: ddtrace.__version__ + style: primary + start: 36 + end: 55 + ? | + import ddtrace + def get_version(): + return ddtrace.__version__ + : labels: + - source: ddtrace.__version__ + style: primary + start: 43 + end: 62 + ? | + import ddtrace + if ddtrace.__version__: + pass + : labels: + - source: ddtrace.__version__ + style: primary + start: 18 + end: 37 + ? | + import ddtrace + print(ddtrace.__version__) + : labels: + - source: ddtrace.__version__ + style: primary + start: 21 + end: 40 + ? |- + import ddtrace + version = ddtrace.__version__ + : labels: + - source: ddtrace.__version__ + style: primary + start: 25 + end: 44 + ? | + import ddtrace + version = ddtrace.__version__ + : labels: + - source: ddtrace.__version__ + style: primary + start: 25 + end: 44 diff --git a/.sg/tests/ddtrace-version-import-test.yml b/.sg/tests/ddtrace-version-import-test.yml new file mode 100644 index 00000000000..9e32a5aed8f --- /dev/null +++ b/.sg/tests/ddtrace-version-import-test.yml @@ -0,0 +1,103 @@ +id: ddtrace-version-import +valid: + # These should NOT trigger the rule (valid code) + # ============================================ + # Direct import from ddtrace.version (correct way) + - from ddtrace.version import __version__ + - from ddtrace.version import __version__ as VERSION + - from ddtrace.version import __version__ as VERSION, get_version + - from ddtrace.version import other, __version__ + # Import version module and access __version__ via attribute (correct way) + - | + from ddtrace import version + v = version.__version__ + - | + import ddtrace.version + v = ddtrace.version.__version__ + - | + import ddtrace.version as ver + v = ver.__version__ + - | + from ddtrace import version as ver + v = ver.__version__ + - | + from ddtrace import version + print(version.__version__) + - | + from ddtrace import version as v + def get_version(): + return v.__version__ + - | + import ddtrace.version + if ddtrace.version.__version__: + pass + # Other imports from ddtrace (not __version__) + - from ddtrace import tracer + - from ddtrace import config, tracer + - from ddtrace import config, tracer, pin + - from ddtrace import tracer, config, pin, span + # Using __version__ that's defined locally (not imported from ddtrace) + - | + __version__ = "1.0.0" + print(__version__) + +invalid: + # These should trigger the rule (errors) + # ====================================== + # Simple direct import cases + - from ddtrace import __version__ + - from ddtrace import __version__ as VERSION + - from ddtrace import __version__ as V + # __version__ at beginning with other items + - from ddtrace import __version__, tracer + - from ddtrace import __version__, config + - from ddtrace import __version__, config, tracer + - from ddtrace import __version__, tracer, config, pin + # __version__ with alias at beginning with other items + - from ddtrace import __version__ as VERSION, tracer + - from ddtrace import __version__ as V, config, tracer + - from ddtrace import __version__ as VERSION, tracer, config, pin + # __version__ at end with other items + - from ddtrace import tracer, __version__ + - from ddtrace import config, __version__ + - from ddtrace import config, tracer, __version__ + - from ddtrace import config, tracer, pin, __version__ + # __version__ with alias at end with other items + - from ddtrace import tracer, __version__ as VERSION + - from ddtrace import config, __version__ as V + - from ddtrace import config, tracer, __version__ as VERSION + - from ddtrace import config, tracer, pin, __version__ as V + # __version__ in middle with other items (2 on each side) + - from ddtrace import config, __version__, tracer + - from ddtrace import config, __version__, tracer, pin + - from ddtrace import tracer, config, __version__, pin, span + # __version__ with alias in middle + - from ddtrace import config, __version__ as VERSION, tracer + - from ddtrace import config, __version__ as V, tracer, pin + - from ddtrace import tracer, config, __version__ as VERSION, pin, span + # Attribute access on ddtrace module (direct __version__ access) + - ddtrace.__version__ + - | + import ddtrace + version = ddtrace.__version__ + - | + from ddtrace import tracer + version = ddtrace.__version__ + # ddtrace.__version__ in various contexts + - | + import ddtrace + print(ddtrace.__version__) + - | + import ddtrace + if ddtrace.__version__: + pass + - | + import ddtrace + compare = ddtrace.__version__ > "1.0" + - | + import ddtrace + config = {"version": ddtrace.__version__} + - | + import ddtrace + def get_version(): + return ddtrace.__version__ diff --git a/MANIFEST.in b/MANIFEST.in index 1baa89a6711..7cfe3f38db1 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,8 @@ +graft ddtrace +graft src + +recursive-exclude * **/__pycache__/* prune .riot/ prune benchmarks/ prune releasenotes/ +prune src/native/target* diff --git a/benchmarks/appsec_iast_aspects/functions.py b/benchmarks/appsec_iast_aspects/functions.py index ebe92461e87..bd8f62d378e 100644 --- a/benchmarks/appsec_iast_aspects/functions.py +++ b/benchmarks/appsec_iast_aspects/functions.py @@ -2,10 +2,13 @@ import os import re -from ddtrace import get_version +try: + from ddtrace import __version__ as version +except ImportError: + from ddtrace import get_version -version = get_version() + version = get_version() # Some old versions could not have or export some symbols, so we import them dynamically and assign None if not found # which will make the aspect benchmark fail but not the entire benchmark diff --git a/benchmarks/appsec_iast_aspects_ospath/functions.py b/benchmarks/appsec_iast_aspects_ospath/functions.py index 1e7fbc324ff..2aa1936ca1e 100644 --- a/benchmarks/appsec_iast_aspects_ospath/functions.py +++ b/benchmarks/appsec_iast_aspects_ospath/functions.py @@ -2,10 +2,13 @@ import os import re -from ddtrace import get_version +try: + from ddtrace import __version__ as version +except ImportError: + from ddtrace import get_version -version = get_version() + version = get_version() # Some old versions could not have or export some symbols, so we import them dynamically and assign None if not found # which will make the aspect benchmark fail but not the entire benchmark diff --git a/benchmarks/appsec_iast_aspects_re_module/functions.py b/benchmarks/appsec_iast_aspects_re_module/functions.py index 4b2c2ebc8cc..5f45dc323da 100644 --- a/benchmarks/appsec_iast_aspects_re_module/functions.py +++ b/benchmarks/appsec_iast_aspects_re_module/functions.py @@ -2,10 +2,13 @@ import os import re -from ddtrace import get_version +try: + from ddtrace import __version__ as version +except ImportError: + from ddtrace import get_version -version = get_version() + version = get_version() # Some old versions could not have or export some symbols, so we import them dynamically and assign None if not found # which will make the aspect benchmark fail but not the entire benchmark diff --git a/benchmarks/appsec_iast_aspects_split/functions.py b/benchmarks/appsec_iast_aspects_split/functions.py index eb32b46e7e3..bfdb30ae0ce 100644 --- a/benchmarks/appsec_iast_aspects_split/functions.py +++ b/benchmarks/appsec_iast_aspects_split/functions.py @@ -2,10 +2,14 @@ import os import re -from ddtrace import get_version +try: + from ddtrace import __version__ as version +except ImportError: + from ddtrace.version import get_version + + version = get_version() -version = get_version() # Some old versions could not have or export some symbols, so we import them dynamically and assign None if not found # which will make the aspect benchmark fail but not the entire benchmark @@ -31,7 +35,7 @@ # print(f"Warning: {symbol} not found in the current version") if notfound_symbols: - print("Warning: symbols not found in the tested version [%s]: %s" % (version.version, str(notfound_symbols))) + print("Warning: symbols not found in the tested version [%s]: %s" % (version, str(notfound_symbols))) def iast_add_aspect(): diff --git a/ddtrace/__init__.py b/ddtrace/__init__.py index dac0448fb68..353448295b9 100644 --- a/ddtrace/__init__.py +++ b/ddtrace/__init__.py @@ -21,16 +21,16 @@ from .internal.compat import PYTHON_VERSION_INFO # noqa: E402 from .internal.settings._config import config from .internal.utils.deprecations import DDTraceDeprecationWarning # noqa: E402 -from .version import get_version # noqa: E402 +from .version import __version__ -__version__ = get_version() - # TODO: Deprecate accessing tracer from ddtrace.__init__ module in v4.0 if os.environ.get("_DD_GLOBAL_TRACER_INIT", "true").lower() in ("1", "true"): from ddtrace.trace import tracer # noqa: F401 + __all__ = [ + "__version__", "patch", "patch_all", "config", diff --git a/ddtrace/_trace/tracer.py b/ddtrace/_trace/tracer.py index 091286187ed..7ea9be3b4df 100644 --- a/ddtrace/_trace/tracer.py +++ b/ddtrace/_trace/tracer.py @@ -59,7 +59,7 @@ from ddtrace.internal.utils.formats import format_trace_id from ddtrace.internal.writer import AgentWriterInterface from ddtrace.internal.writer import HTTPWriter -from ddtrace.version import get_version +from ddtrace.version import __version__ log = get_logger(__name__) @@ -165,7 +165,7 @@ def __init__(self) -> None: metadata = PyTracerMetadata( runtime_id=get_runtime_id(), - tracer_version=get_version(), + tracer_version=__version__, hostname=get_hostname(), service_name=config.service or None, service_env=config.env or None, diff --git a/ddtrace/appsec/ai_guard/_api_client.py b/ddtrace/appsec/ai_guard/_api_client.py index a551a8288dd..d24a7814dc0 100644 --- a/ddtrace/appsec/ai_guard/_api_client.py +++ b/ddtrace/appsec/ai_guard/_api_client.py @@ -7,7 +7,6 @@ from typing import Optional # noqa:F401 from typing import TypedDict -import ddtrace from ddtrace import config from ddtrace import tracer as ddtracer from ddtrace._trace.tracer import Tracer @@ -19,6 +18,7 @@ from ddtrace.internal.telemetry.metrics_namespaces import MetricTagType from ddtrace.internal.utils.http import Response from ddtrace.internal.utils.http import get_connection +from ddtrace.version import __version__ logger = ddlogger.get_logger(__name__) @@ -99,7 +99,7 @@ def __init__(self, endpoint: str, api_key: str, app_key: str, tracer: Tracer): "Content-Type": "application/json", "DD-API-KEY": api_key, "DD-APPLICATION-KEY": app_key, - "DD-AI-GUARD-VERSION": ddtrace.__version__, + "DD-AI-GUARD-VERSION": __version__, "DD-AI-GUARD-SOURCE": "SDK", "DD-AI-GUARD-LANGUAGE": "python", } diff --git a/ddtrace/commands/ddtrace_run.py b/ddtrace/commands/ddtrace_run.py index b88199b1e7f..e297134e877 100755 --- a/ddtrace/commands/ddtrace_run.py +++ b/ddtrace/commands/ddtrace_run.py @@ -8,6 +8,7 @@ import typing # noqa:F401 import ddtrace +from ddtrace.version import __version__ def _find_executable(args: typing.Optional[argparse.Namespace]) -> typing.Optional[str]: @@ -70,7 +71,7 @@ def _get_arg_parser() -> argparse.ArgumentParser: action="store_true", ) parser.add_argument("-p", "--profiling", help="enable profiling (disabled by default)", action="store_true") - parser.add_argument("-v", "--version", action="version", version="%(prog)s " + ddtrace.__version__) + parser.add_argument("-v", "--version", action="version", version="%(prog)s " + __version__) parser.add_argument("-nc", "--colorless", help="print output of command without color", action="store_true") return parser diff --git a/ddtrace/internal/ci_visibility/filters.py b/ddtrace/internal/ci_visibility/filters.py index f4b96fbe88e..88066635374 100644 --- a/ddtrace/internal/ci_visibility/filters.py +++ b/ddtrace/internal/ci_visibility/filters.py @@ -4,12 +4,12 @@ from typing import Optional # noqa:F401 from typing import Union # noqa:F401 -import ddtrace from ddtrace.ext import SpanTypes from ddtrace.ext import ci from ddtrace.internal.constants import SamplingMechanism from ddtrace.internal.sampling import _set_sampling_tags from ddtrace.trace import TraceFilter +from ddtrace.version import __version__ if TYPE_CHECKING: @@ -35,6 +35,6 @@ def process_trace(self, trace): _set_sampling_tags(local_root, True, 1.0, SamplingMechanism.DEFAULT) for span in trace: span.set_tags(self._tags) - span._set_tag_str(ci.LIBRARY_VERSION, ddtrace.__version__) + span._set_tag_str(ci.LIBRARY_VERSION, __version__) return trace diff --git a/ddtrace/internal/ci_visibility/writer.py b/ddtrace/internal/ci_visibility/writer.py index e6181c58ac9..4d7b6043c18 100644 --- a/ddtrace/internal/ci_visibility/writer.py +++ b/ddtrace/internal/ci_visibility/writer.py @@ -5,7 +5,6 @@ from typing import Dict from typing import Optional # noqa:F401 -import ddtrace from ddtrace import config from ddtrace.ext import SpanTypes from ddtrace.ext.test import TEST_SESSION_NAME @@ -15,6 +14,7 @@ from ddtrace.internal.settings._agent import config as agent_config from ddtrace.internal.utils.time import StopWatch from ddtrace.vendor.dogstatsd import DogStatsd # noqa:F401 +from ddtrace.version import __version__ from .. import service from ..evp_proxy.constants import EVP_PROXY_AGENT_ENDPOINT @@ -53,7 +53,7 @@ def __init__(self): "language": "python", "env": os.getenv("_CI_DD_ENV", config.env), "runtime-id": get_runtime_id(), - "library_version": ddtrace.__version__, + "library_version": __version__, "_dd.test.is_user_provided_service": "true" if config._is_user_provided_service else "false", }, ) diff --git a/ddtrace/internal/core/crashtracking.py b/ddtrace/internal/core/crashtracking.py index 89d68bc99d2..8b3a041f00d 100644 --- a/ddtrace/internal/core/crashtracking.py +++ b/ddtrace/internal/core/crashtracking.py @@ -54,7 +54,7 @@ def _get_tags(additional_tags: Optional[Dict[str, str]]) -> Dict[str, str]: runtime_version = platform.python_version() if runtime_version: tags["runtime_version"] = runtime_version - library_version = version.get_version() + library_version = version.__version__ if library_version: tags["library_version"] = library_version if process_tags: @@ -130,7 +130,7 @@ def _get_args(additional_tags: Optional[Dict[str, str]]): tags = _get_tags(additional_tags) - metadata = CrashtrackerMetadata("dd-trace-py", version.get_version(), "python", tags) + metadata = CrashtrackerMetadata("dd-trace-py", version.__version__, "python", tags) return config, receiver_config, metadata diff --git a/ddtrace/internal/datastreams/processor.py b/ddtrace/internal/datastreams/processor.py index 83db2876f44..52a5ae49e94 100644 --- a/ddtrace/internal/datastreams/processor.py +++ b/ddtrace/internal/datastreams/processor.py @@ -23,7 +23,7 @@ from ddtrace.internal.settings._agent import config as agent_config from ddtrace.internal.settings._config import config from ddtrace.internal.utils.retry import fibonacci_backoff_with_jitter -from ddtrace.version import get_version +from ddtrace.version import __version__ from .._encoding import packb from ..agent import get_connection @@ -114,7 +114,7 @@ def __init__( # Have the bucket size match the interval in which flushes occur. self._bucket_size_ns = int(interval * 1e9) # type: int self._buckets = defaultdict(lambda: Bucket(defaultdict(PathwayStats), defaultdict(int), defaultdict(int))) # type: DefaultDict[int, Bucket] - self._version = get_version() + self._version = __version__ self._headers = { "Datadog-Meta-Lang": "python", "Datadog-Meta-Tracer-Version": self._version, diff --git a/ddtrace/internal/debug.py b/ddtrace/internal/debug.py index 4d174d278a1..c8512d4d462 100644 --- a/ddtrace/internal/debug.py +++ b/ddtrace/internal/debug.py @@ -15,6 +15,7 @@ from ddtrace.internal.utils.cache import callonce from ddtrace.internal.writer import AgentWriterInterface from ddtrace.internal.writer import LogWriter +from ddtrace.version import __version__ from .logger import get_logger @@ -119,7 +120,7 @@ def collect(tracer): is_64_bit=sys.maxsize > 2**32, architecture=architecture()[0], vm=platform.python_implementation(), - version=ddtrace.__version__, + version=__version__, lang="python", lang_version=platform.python_version(), pip_version=pip_version, diff --git a/ddtrace/internal/processor/stats.py b/ddtrace/internal/processor/stats.py index ea2227aee1b..0ad1397c1e6 100644 --- a/ddtrace/internal/processor/stats.py +++ b/ddtrace/internal/processor/stats.py @@ -14,7 +14,7 @@ from ddtrace.internal.native import DDSketch from ddtrace.internal.settings._config import config from ddtrace.internal.utils.retry import fibonacci_backoff_with_jitter -from ddtrace.version import get_version +from ddtrace.version import __version__ from ...constants import _SPAN_MEASURED_KEY from .. import agent @@ -105,7 +105,7 @@ def __init__( ) self._headers: Dict[str, str] = { "Datadog-Meta-Lang": "python", - "Datadog-Meta-Tracer-Version": get_version(), + "Datadog-Meta-Tracer-Version": __version__, "Content-Type": "application/msgpack", } self._hostname = "" diff --git a/ddtrace/internal/runtime/tag_collectors.py b/ddtrace/internal/runtime/tag_collectors.py index 9cbe857446d..bf0943e3ea0 100644 --- a/ddtrace/internal/runtime/tag_collectors.py +++ b/ddtrace/internal/runtime/tag_collectors.py @@ -63,16 +63,16 @@ class PlatformTagCollector(RuntimeTagCollector): - ``tracer_version`` e.g. ``0.29.0`` """ - required_modules = ["platform", "ddtrace"] + required_modules = ["platform", "ddtrace.version"] def collect_fn(self, keys): platform = self.modules.get("platform") - ddtrace = self.modules.get("ddtrace") + version = self.modules.get("ddtrace.version") tags = [ (LANG, "python"), (LANG_INTERPRETER, platform.python_implementation()), (LANG_VERSION, platform.python_version()), - (TRACER_VERSION, ddtrace.__version__), + (TRACER_VERSION, version.__version__), ] return tags diff --git a/ddtrace/internal/settings/dynamic_instrumentation.py b/ddtrace/internal/settings/dynamic_instrumentation.py index 2ee9a3072c3..9876268ecbf 100644 --- a/ddtrace/internal/settings/dynamic_instrumentation.py +++ b/ddtrace/internal/settings/dynamic_instrumentation.py @@ -8,7 +8,7 @@ from ddtrace.internal.settings._agent import config as agent_config from ddtrace.internal.settings._core import DDConfig from ddtrace.internal.utils.config import get_application_name -from ddtrace.version import get_version +from ddtrace.version import __version__ DEFAULT_GLOBAL_RATE_LIMIT = 100.0 @@ -16,7 +16,7 @@ def _derive_tags(c): # type: (DDConfig) -> str - _tags = dict(env=ddconfig.env, version=ddconfig.version, debugger_version=get_version()) + _tags = dict(env=ddconfig.env, version=ddconfig.version, debugger_version=__version__) _tags.update(ddconfig.tags) # Add git metadata tags, if available diff --git a/ddtrace/internal/telemetry/data.py b/ddtrace/internal/telemetry/data.py index 30d5a153c7e..060b766d7cc 100644 --- a/ddtrace/internal/telemetry/data.py +++ b/ddtrace/internal/telemetry/data.py @@ -12,7 +12,7 @@ from ddtrace.internal.packages import get_module_distribution_versions from ddtrace.internal.runtime.container import get_container_info from ddtrace.internal.utils.cache import cached -from ddtrace.version import get_version +from ddtrace.version import __version__ from ..hostname import get_hostname @@ -65,7 +65,7 @@ def _get_application(key): "env": env or "", "language_name": "python", "language_version": _format_version_info(sys.version_info), - "tracer_version": get_version(), + "tracer_version": __version__, "runtime_name": platform.python_implementation(), "runtime_version": _format_version_info(sys.implementation.version), } diff --git a/ddtrace/internal/utils/version.py b/ddtrace/internal/utils/version.py index b3ab75d5ef4..be10973b63f 100644 --- a/ddtrace/internal/utils/version.py +++ b/ddtrace/internal/utils/version.py @@ -2,7 +2,7 @@ from typing import Optional # noqa:F401 import ddtrace.vendor.packaging.version as packaging_version -from ddtrace.version import get_version +from ddtrace.version import __version__ def parse_version(version): @@ -71,7 +71,7 @@ def _pep440_to_semver(version=None): # # e.g. 1.7.1-rc2.dev3+gf258c7d9 is valid - tracer_version = version or get_version() + tracer_version = version or __version__ if "rc" in tracer_version and "-rc" not in tracer_version: tracer_version = tracer_version.replace("rc", "-rc", 1) elif ".dev" in tracer_version: diff --git a/ddtrace/internal/writer/writer.py b/ddtrace/internal/writer/writer.py index 9aad9ca77fa..014e73f94d6 100644 --- a/ddtrace/internal/writer/writer.py +++ b/ddtrace/internal/writer/writer.py @@ -13,7 +13,6 @@ from typing import Optional from typing import TextIO -import ddtrace from ddtrace import config from ddtrace.internal.dist_computing.utils import in_ray_job from ddtrace.internal.hostname import get_hostname @@ -23,6 +22,7 @@ from ddtrace.internal.settings.asm import ai_guard_config from ddtrace.internal.settings.asm import config as asm_config from ddtrace.internal.utils.retry import fibonacci_backoff_with_jitter +from ddtrace.version import __version__ from ...constants import _KEEP_SPANS_RATE_KEY from .. import compat @@ -575,7 +575,7 @@ def __init__( "Datadog-Meta-Lang": "python", "Datadog-Meta-Lang-Version": compat.PYTHON_VERSION, "Datadog-Meta-Lang-Interpreter": compat.PYTHON_INTERPRETER, - "Datadog-Meta-Tracer-Version": ddtrace.__version__, + "Datadog-Meta-Tracer-Version": __version__, "Datadog-Client-Computed-Top-Level": "yes", } if headers: @@ -801,7 +801,7 @@ def _create_exporter(self) -> native.TraceExporter: .set_language("python") .set_language_version(compat.PYTHON_VERSION) .set_language_interpreter(compat.PYTHON_INTERPRETER) - .set_tracer_version(ddtrace.__version__) + .set_tracer_version(__version__) .set_git_commit_sha(commit_sha) .set_client_computed_top_level() .set_input_format(self._api_version) diff --git a/ddtrace/llmobs/_experiment.py b/ddtrace/llmobs/_experiment.py index 3ea2bb3ec00..ad6e21c59fb 100644 --- a/ddtrace/llmobs/_experiment.py +++ b/ddtrace/llmobs/_experiment.py @@ -17,7 +17,6 @@ from typing import overload import uuid -import ddtrace from ddtrace import config from ddtrace.constants import ERROR_MSG from ddtrace.constants import ERROR_STACK @@ -27,6 +26,7 @@ from ddtrace.llmobs._constants import EXPERIMENT_EXPECTED_OUTPUT from ddtrace.llmobs._utils import convert_tags_dict_to_list from ddtrace.llmobs._utils import safe_json +from ddtrace.version import __version__ if TYPE_CHECKING: @@ -360,7 +360,7 @@ def __init__( self._summary_evaluators = summary_evaluators or [] self._description = description self._tags: Dict[str, str] = tags or {} - self._tags["ddtrace.version"] = str(ddtrace.__version__) + self._tags["ddtrace.version"] = str(__version__) self._config: Dict[str, JSONType] = config or {} self._runs: int = runs or 1 self._llmobs_instance = _llmobs_instance diff --git a/ddtrace/llmobs/_llmobs.py b/ddtrace/llmobs/_llmobs.py index 94a5e421975..f4d5d731aaf 100644 --- a/ddtrace/llmobs/_llmobs.py +++ b/ddtrace/llmobs/_llmobs.py @@ -122,6 +122,7 @@ from ddtrace.llmobs.utils import Messages from ddtrace.llmobs.utils import extract_tool_definitions from ddtrace.propagation.http import HTTPPropagator +from ddtrace.version import __version__ log = get_logger(__name__) @@ -466,7 +467,7 @@ def _llmobs_tags(span: Span, ml_app: str, session_id: Optional[str] = None) -> L "service": span.service or "", "source": "integration", "ml_app": ml_app, - "ddtrace.version": ddtrace.__version__, + "ddtrace.version": __version__, "language": "python", "error": span.error, } @@ -1744,7 +1745,7 @@ def submit_evaluation( ) evaluation_tags = { - "ddtrace.version": ddtrace.__version__, + "ddtrace.version": __version__, "ml_app": ml_app, } diff --git a/ddtrace/llmobs/_writer.py b/ddtrace/llmobs/_writer.py index 7d956310763..db88a0a6f1d 100644 --- a/ddtrace/llmobs/_writer.py +++ b/ddtrace/llmobs/_writer.py @@ -15,7 +15,6 @@ from urllib.parse import quote from urllib.parse import urlparse -import ddtrace from ddtrace import config from ddtrace.internal import agent from ddtrace.internal import forksafe @@ -49,6 +48,7 @@ from ddtrace.llmobs._utils import safe_json from ddtrace.llmobs.types import _Meta from ddtrace.llmobs.types import _SpanLink +from ddtrace.version import __version__ logger = get_logger(__name__) @@ -723,7 +723,7 @@ def _data(self, events: List[LLMObsSpanEvent]) -> List[Dict[str, Any]]: for event in events: event_data = { "_dd.stage": "raw", - "_dd.tracer_version": ddtrace.__version__, + "_dd.tracer_version": __version__, "event_type": "span", "spans": [event], } diff --git a/ddtrace/version.py b/ddtrace/version.py index 016f71773e4..a688dcc6383 100644 --- a/ddtrace/version.py +++ b/ddtrace/version.py @@ -1,13 +1,13 @@ -def get_version() -> str: - try: - from ._version import version - - return version - except ImportError: - from importlib.metadata import version as ilm_version - - try: - return ilm_version("ddtrace") - except ModuleNotFoundError: - # package is not installed - return "dev" +"""Maintain a separate module for the version to avoid circular imports.""" + +import importlib.metadata + + +__all__ = ["__version__"] + +__version__: str + +try: + __version__ = importlib.metadata.version(__package__ or __name__) +except importlib.metadata.PackageNotFoundError: + __version__ = "0.0.0" diff --git a/docs/build_system.rst b/docs/build_system.rst index 4670e5ae15c..c633555e7d2 100644 --- a/docs/build_system.rst +++ b/docs/build_system.rst @@ -41,13 +41,13 @@ To see the current build dependencies, check the `[build-system]` section in the .. code-block:: toml [build-system] - requires = ["setuptools_scm[toml]>=4", "cython", "cmake>=3.24.2,<3.28; python_version>='3.8'", "setuptools-rust<2"] + requires = ["cython", "cmake>=3.24.2,<3.28; python_version>='3.8'", "setuptools-rust<2"] To install all dependencies in one step, use: .. code-block:: bash - pip install 'setuptools_scm[toml]>=4' 'cython' 'cmake>=3.24.2,<3.28' 'setuptools-rust<2' + pip install 'cython' 'cmake>=3.24.2,<3.28' 'setuptools-rust<2' Note that `pip install -e` (described below) also installs these build dependencies automatically. diff --git a/pyproject.toml b/pyproject.toml index 0d96d70749f..5d6072217c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,5 @@ [build-system] requires = [ - "setuptools_scm[toml]>=4", "cython", "cmake>=3.24.2,<3.28; python_version>='3.8'", "setuptools-rust<2", @@ -10,10 +9,7 @@ build-backend = "setuptools.build_meta" [project] name = "ddtrace" -# DEV: to directly override the version specifier, comment this... -#dynamic = ["version"] -# ...and uncomment this -version = "4.1.0dev" +version = "4.1.0.dev0" description = "Datadog APM client library" readme = "README.md" license = { text = "LICENSE.BSD3" } @@ -83,10 +79,6 @@ Documentation = "https://ddtrace.readthedocs.io/en/stable/" Homepage = "https://github.com/DataDog/dd-trace-py" "Source Code" = "https://github.com/DataDog/dd-trace-py/" -[tool.setuptools_scm] -version_scheme = "release-branch-semver" # Must be "release-branch-semver" for now in main, see https://github.com/DataDog/dd-trace-py/issues/8801 -write_to = "ddtrace/_version.py" - [tool.cython-lint] max-line-length = 120 exclude = ''' diff --git a/scripts/ddtest b/scripts/ddtest index d3b8f7eb821..9bbd5148fe0 100755 --- a/scripts/ddtest +++ b/scripts/ddtest @@ -9,24 +9,8 @@ then CMD=bash fi -# If we are in a worktree inside of the container then git/setuptools_scm doesn't work right -# we need to tell setuptools_scm what the version is manually -if git rev-parse --is-inside-work-tree > /dev/null 2>&1 -then - if command -v uv > /dev/null 2>&1 - then - version=$(uvx --from=setuptools_scm --quiet setuptools-scm) - else - version=$(git describe --tags --abbrev=0 --match "v[0-9]*" | sed 's/^v//') - fi - - export SETUPTOOLS_SCM_PRETEND_VERSION_FOR_DDTRACE="${version}" -fi - docker compose run \ -e DD_TRACE_AGENT_URL \ - -e SETUPTOOLS_SCM_PRETEND_VERSION \ - -e SETUPTOOLS_SCM_PRETEND_VERSION_FOR_DDTRACE \ --rm \ -i \ testrunner \ diff --git a/scripts/gen_gitlab_config.py b/scripts/gen_gitlab_config.py index dae89780119..afc29068e44 100755 --- a/scripts/gen_gitlab_config.py +++ b/scripts/gen_gitlab_config.py @@ -283,6 +283,11 @@ def check(name: str, command: str, paths: t.Set[str]) -> None: command="scripts/check-dependency-bounds", paths={"pyproject.toml"}, ) + check( + name="Check package version", + command="scripts/verify-package-version", + paths={"pyproject.toml"}, + ) check( name="Check for namespace packages", command="scripts/check-for-namespace-packages.sh", diff --git a/scripts/verify-package-version b/scripts/verify-package-version new file mode 100755 index 00000000000..d258c482c50 --- /dev/null +++ b/scripts/verify-package-version @@ -0,0 +1,78 @@ +#!/usr/bin/env scripts/uv-run-script +# -*- mode: python -*- +# /// script +# requires-python = ">=3.9" +# dependencies = ["packaging"] +# /// +"""Verify that the version in pyproject.toml is PEP 440 compliant. + +Performs the following validation: +- Ensures version in pyproject.toml is PEP 440 compliant (e.g., "4.1.0.dev0" not "4.1.0.dev") + +Usage: + scripts/verify-package-version # Check version compliance (exit 0 if OK, 1 if not compliant) +""" + +import sys +from pathlib import Path + +from packaging.version import InvalidVersion +from packaging.version import Version + +try: + import tomllib +except ModuleNotFoundError: + import tomli as tomllib # type: ignore[import-not-found] + + +def is_pep440_compliant(version_str: str) -> tuple[bool, str]: + """Check if a version string is strictly PEP 440 compliant. + + Returns: + Tuple of (is_compliant, normalized_version) + """ + try: + parsed = Version(version_str) + normalized = str(parsed) + + # Check if the original matches the normalized form + # If they differ, the version had implicit defaults which is not strictly compliant + is_compliant = version_str == normalized + return is_compliant, normalized + except InvalidVersion: + return False, "" + + +def read_pyproject_version(pyproject_path: Path) -> str: + """Read version from pyproject.toml.""" + with open(pyproject_path, "rb") as f: + data = tomllib.load(f) + return data["project"]["version"] + + +def main() -> int: + """Main entry point.""" + repo_root = Path(__file__).parent.parent + pyproject_path = repo_root / "pyproject.toml" + + try: + pyproject_version = read_pyproject_version(pyproject_path) + + # Check PEP 440 compliance + is_compliant, normalized_version = is_pep440_compliant(pyproject_version) + if not is_compliant: + print(f"✗ Version in pyproject.toml is not PEP 440 compliant: {pyproject_version}", file=sys.stderr) + print(f" PEP 440 requires explicit numbers for pre-release, post, and dev versions", file=sys.stderr) + print(f" Suggested fix: {normalized_version}", file=sys.stderr) + return 1 + + print(f"✓ Version {pyproject_version} is PEP 440 compliant") + return 0 + + except Exception as e: + print(f"✗ Error: {e}", file=sys.stderr) + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tests/appsec/architectures/mini.py b/tests/appsec/architectures/mini.py index 179c85bfb80..3d7b8419273 100644 --- a/tests/appsec/architectures/mini.py +++ b/tests/appsec/architectures/mini.py @@ -11,9 +11,9 @@ from flask import request # noqa: E402 import requests # noqa: E402 F401 +from ddtrace import __version__ # noqa: E402 from ddtrace.internal.settings.asm import config as asm_config # noqa: E402 import ddtrace.internal.telemetry.writer # noqa: E402 -from ddtrace.version import get_version # noqa: E402 app = Flask(__name__) @@ -46,7 +46,7 @@ def hello_world(): k: getattr(asm_config, k) for k in dir(asm_config) if isinstance(getattr(asm_config, k), (int, bool, float)) }, "aws": "AWS_LAMBDA_FUNCTION_NAME" in os.environ, - "version": get_version(), + "version": __version__, "env": dict(os.environ), "file_length": file_length, } diff --git a/tests/appsec/contrib_appsec/conftest.py b/tests/appsec/contrib_appsec/conftest.py index 951465bedcf..53a44674a7f 100644 --- a/tests/appsec/contrib_appsec/conftest.py +++ b/tests/appsec/contrib_appsec/conftest.py @@ -3,7 +3,7 @@ # ensure the tracer is loaded and started first for possible iast patching -print(f"ddtrace version {ddtrace.version.get_version()}") +print(f"ddtrace version {ddtrace.version.__version__}") import pytest # noqa: E402 diff --git a/tests/contrib/patch.py b/tests/contrib/patch.py index 1e15cc9a828..cc20c745c14 100644 --- a/tests/contrib/patch.py +++ b/tests/contrib/patch.py @@ -8,14 +8,14 @@ from textwrap import dedent import unittest +from ddtrace import __version__ from ddtrace.internal.compat import is_wrapted -from ddtrace.version import get_version from tests.subprocesstest import SubprocessTestCase from tests.subprocesstest import run_in_subprocess from tests.utils import call_program -TRACER_VERSION = get_version() +TRACER_VERSION = __version__ class PatchMixin(unittest.TestCase): diff --git a/tests/debugging/test_config.py b/tests/debugging/test_config.py index 07c8ef7d739..563df5f5eae 100644 --- a/tests/debugging/test_config.py +++ b/tests/debugging/test_config.py @@ -2,10 +2,10 @@ import pytest +from ddtrace import __version__ from ddtrace.internal.settings._agent import config as agent_config from ddtrace.internal.settings.dynamic_instrumentation import DynamicInstrumentationConfig from ddtrace.internal.utils.formats import parse_tags_str -from ddtrace.version import get_version from tests.utils import override_env @@ -39,7 +39,7 @@ def test_tags(): c="d", env="test-env", version="test-version", - debugger_version=get_version(), + debugger_version=__version__, ) diff --git a/tests/lib_injection/conftest.py b/tests/lib_injection/conftest.py index fa7ed195bbe..94ead44a978 100644 --- a/tests/lib_injection/conftest.py +++ b/tests/lib_injection/conftest.py @@ -13,10 +13,10 @@ import pytest -from ddtrace.version import get_version +from ddtrace import __version__ -HOST_DDTRACE_VERSION = get_version() +HOST_DDTRACE_VERSION = __version__ LIBS_INJECTION_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../lib-injection")) LIBS_INJECTION_SRC_DIR = os.path.join(LIBS_INJECTION_DIR, "sources") PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")) diff --git a/tests/suitespec.yml b/tests/suitespec.yml index 2ab099d3878..4358496c03b 100644 --- a/tests/suitespec.yml +++ b/tests/suitespec.yml @@ -76,7 +76,6 @@ components: - ddtrace/__init__.py - ddtrace/py.typed - ddtrace/version.py - - ddtrace/_version.py - ddtrace/internal/settings/_config.py - src/native/* datastreams: diff --git a/tests/tracer/test_version.py b/tests/tracer/test_version.py deleted file mode 100644 index 5ab2033b459..00000000000 --- a/tests/tracer/test_version.py +++ /dev/null @@ -1,41 +0,0 @@ -import sys - -import mock - -from ddtrace.version import get_version -from tests.tracer import _version # noqa: F401 -> we need to import it so that it can be swapped with the test module - - -def test_get_version_from_version_file(): - with mock.patch.dict(sys.modules, {"ddtrace._version": sys.modules["tests.tracer._version"]}): - assert get_version() == "my_test_version_from_generated_file" - - -def test_get_version_from_importlib_metadata(): - with mock.patch.dict(sys.modules, {"ddtrace._version": None}): - version_str = "importlib.metadata.version" - with mock.patch(version_str, return_value="my_test_version_from_import_lib") as mock_get_version: - assert get_version() == "my_test_version_from_import_lib" - mock_get_version.assert_called_with("ddtrace") - - -def test_get_version_dev_fallback(): - with mock.patch.dict(sys.modules, {"ddtrace._version": None}): - version_str = "importlib.metadata.version" - with mock.patch(version_str, side_effect=ModuleNotFoundError): - assert get_version() == "dev" - - -class FakeDistributionIterator: - def __init__(self, distribution): - pass - - def __next__(self): - raise StopIteration - - -class FakeDistribution: - version = "my_test_version_from_pkg_resources" - - def __iter__(self): - return FakeDistributionIterator(self)