From 54095634fd3d1a4fa1858597f15f8f738ac29ac2 Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Tue, 16 Mar 2021 13:43:02 -0400 Subject: [PATCH 01/10] Enabled type hinting/checking for context, monkey, span, helpers --- ddtrace/context.py | 29 ++++++++++++++---- ddtrace/helpers.py | 5 ++++ ddtrace/monkey.py | 12 +++++++- ddtrace/span.py | 74 ++++++++++++++++++++++++++++++---------------- ddtrace/tracer.py | 5 ++-- 5 files changed, 90 insertions(+), 35 deletions(-) diff --git a/ddtrace/context.py b/ddtrace/context.py index 3a501b0257a..ea7fd3179fe 100644 --- a/ddtrace/context.py +++ b/ddtrace/context.py @@ -1,8 +1,12 @@ import threading +from typing import List +from typing import Optional +from typing import Tuple from .constants import ORIGIN_KEY from .constants import SAMPLING_PRIORITY_KEY from .internal.logger import get_logger +from .span import Span from .utils.formats import asbool from .utils.formats import get_env @@ -29,16 +33,23 @@ class Context(object): _partial_flush_enabled = asbool(get_env("tracer", "partial_flush_enabled", default=False)) _partial_flush_min_spans = int(get_env("tracer", "partial_flush_min_spans", default=500)) - def __init__(self, trace_id=None, span_id=None, sampling_priority=None, dd_origin=None): + def __init__( + self, + trace_id=None, # type: Optional[int] + span_id=None, # type: Optional[int] + sampling_priority=None, # type: Optional[int] + dd_origin=None, # type: Optional[str] + ): + # type: (...) -> None """ Initialize a new thread-safe ``Context``. :param int trace_id: trace_id of parent span :param int span_id: span_id of parent span """ - self._trace = [] + self._trace = [] # type: List[Span] self._finished_spans = 0 - self._current_span = None + self._current_span = None # type: Optional[Span] self._lock = threading.Lock() self._parent_trace_id = trace_id @@ -66,11 +77,13 @@ def sampling_priority(self): @sampling_priority.setter def sampling_priority(self, value): + # type: (int) -> None """Set sampling priority.""" with self._lock: self._sampling_priority = value def clone(self): + # type: () -> Context """ Partially clones the current context. It copies everything EXCEPT the registered and finished spans. @@ -85,12 +98,14 @@ def clone(self): return new_ctx def get_current_root_span(self): + # type: () -> Optional[Span] """ Return the root span of the context or None if it does not exist. """ return self._trace[0] if len(self._trace) > 0 else None def get_current_span(self): + # type: () -> Optional[Span] """ Return the last active span that corresponds to the last inserted item in the trace list. This cannot be considered as the current active @@ -101,6 +116,7 @@ def get_current_span(self): return self._current_span def _set_current_span(self, span): + # type: (Optional[Span]) -> None """ Set current span internally. @@ -114,16 +130,19 @@ def _set_current_span(self, span): self._parent_span_id = None def add_span(self, span): + # type: (Optional[Span]) -> None """ Add a span to the context trace list, keeping it as the last active span. """ with self._lock: self._set_current_span(span) - self._trace.append(span) - span._context = self + # TODO: Check if span is None + self._trace.append(span) # type: ignore + span._context = self # type: ignore def close_span(self, span): + # type: (Span) -> Tuple[Optional[List[Span]], Optional[bool]] """ Mark a span as a finished, increasing the internal counter to prevent cycles inside _trace list. diff --git a/ddtrace/helpers.py b/ddtrace/helpers.py index 3374b415f55..aa2c182fb74 100644 --- a/ddtrace/helpers.py +++ b/ddtrace/helpers.py @@ -1,7 +1,12 @@ +from typing import Optional +from typing import Tuple + import ddtrace +from ddtrace.tracer import Tracer def get_correlation_ids(tracer=None): + # type: (Optional[Tracer]) -> Tuple[Optional[int], Optional[int]] """Retrieves the Correlation Identifiers for the current active ``Trace``. This helper method can be achieved manually and should be considered only a shortcut. The main reason is to abstract the current ``Tracer`` diff --git a/ddtrace/monkey.py b/ddtrace/monkey.py index 66fa8d81926..3f54e8bc90f 100644 --- a/ddtrace/monkey.py +++ b/ddtrace/monkey.py @@ -10,6 +10,10 @@ import os import sys import threading +from typing import Any +from typing import Callable +from typing import Dict +from typing import List from ddtrace.vendor.wrapt.importer import when_imported @@ -103,6 +107,7 @@ class ModuleNotFoundException(PatchException): def _on_import_factory(module, raise_errors=True): + # type: (str, bool) -> Callable[[Any], None] """Factory to create an import hook for the provided module name""" def on_import(hook): @@ -115,6 +120,7 @@ def on_import(hook): def patch_all(**patch_modules): + # type: (Dict[str, bool]) -> None """Automatically patches all available modules. In addition to ``patch_modules``, an override can be specified via an @@ -144,6 +150,7 @@ def patch_all(**patch_modules): def patch(raise_errors=True, **patch_modules): + # type: (bool, Dict[str, bool]) -> None """Patch only a set of given modules. :param bool raise_errors: Raise error if one patch fail. @@ -179,6 +186,7 @@ def patch(raise_errors=True, **patch_modules): def patch_module(module, raise_errors=True): + # type: (str, bool) -> bool """Patch a single module Returns if the module got properly patched. @@ -197,12 +205,14 @@ def patch_module(module, raise_errors=True): def get_patched_modules(): + # type: () -> List[str] """Get the list of patched modules""" with _LOCK: return sorted(_PATCHED_MODULES) def _patch_module(module): + # type: (str) -> bool """_patch_module will attempt to monkey patch the module. Returns if the module got patched. @@ -225,6 +235,6 @@ def _patch_module(module): if not hasattr(imported_module, "patch"): raise ModuleNotFoundException("module '%s' not installed" % module) - imported_module.patch() + imported_module.patch() # type: ignore _PATCHED_MODULES.add(module) return True diff --git a/ddtrace/span.py b/ddtrace/span.py index a699aae67f4..3de528cf3a2 100644 --- a/ddtrace/span.py +++ b/ddtrace/span.py @@ -1,6 +1,8 @@ import math import sys import traceback +from typing import Any +from typing import Dict from typing import List from typing import Optional @@ -17,6 +19,7 @@ from .constants import SERVICE_VERSION_KEY from .constants import SPAN_MEASURED_KEY from .constants import VERSION_KEY +from .context import Context from .ext import SpanTypes from .ext import errors from .ext import http @@ -24,6 +27,7 @@ from .ext import priority from .internal import _rand from .internal.logger import get_logger +from .tracer import Tracer from .vendor import six @@ -58,18 +62,19 @@ class Span(object): def __init__( self, - tracer, - name, - service=None, - resource=None, - span_type=None, - trace_id=None, - span_id=None, - parent_id=None, - start=None, - context=None, - _check_pid=True, + tracer, # type: Tracer + name, # type: str + service=None, # type: Optional[str] + resource=None, # type: Optional[str] + span_type=None, # type: Optional[str] + trace_id=None, # type: Optional[int] + span_id=None, # type: Optional[int] + parent_id=None, # type: Optional[int] + start=None, # type: Optional[int] + context=None, # type: Optional[Context] + _check_pid=True, # type: bool ): + # type: (...) -> None """ Create a new span. Call `finish` once the traced operation is over. @@ -96,25 +101,25 @@ def __init__( self.span_type = span_type # tags / metadata - self.meta = {} + self.meta = {} # type: Dict[str, Any] self.error = 0 - self.metrics = {} + self.metrics = {} # type: Dict[str, Any] # timing self.start_ns = time_ns() if start is None else int(start * 1e9) - self.duration_ns = None + self.duration_ns = None # type: Optional[int] # tracing - self.trace_id = trace_id or _rand.rand64bits(check_pid=_check_pid) - self.span_id = span_id or _rand.rand64bits(check_pid=_check_pid) - self.parent_id = parent_id + self.trace_id = trace_id or _rand.rand64bits(check_pid=_check_pid) # type: int + self.span_id = span_id or _rand.rand64bits(check_pid=_check_pid) # type: int + self.parent_id = parent_id # type: Optional[int] self.tracer = tracer # sampling - self.sampled = True + self.sampled = True # type: bool self._context = context - self._parent = None + self._parent = None # type: Optional[Span] self._ignored_exceptions = None # type: Optional[List[Exception]] def _ignore_exception(self, exc): @@ -147,6 +152,7 @@ def finished(self): @finished.setter def finished(self, value): + # type: (bool) -> None """Finishes the span if set to a truthy value. If the span is already finished and a truthy value is provided @@ -166,9 +172,11 @@ def duration(self): @duration.setter def duration(self, value): - self.duration_ns = value * 1e9 + # type: (int) -> None + self.duration_ns = value * 1e9 # type: ignore def finish(self, finish_time=None): + # type: (Optional[int]) -> None """Mark the end time of the span and submit it to the tracer. If the span has already been finished don't do anything @@ -189,6 +197,7 @@ def finish(self, finish_time=None): self.tracer.write(trace) def set_tag(self, key, value=None): + # type: (str, Any) -> None """Set a tag key/value pair on the span. Keys must be strings, values must be ``stringify``-able. @@ -217,13 +226,13 @@ def set_tag(self, key, value=None): INT_TYPES = (net.TARGET_PORT,) if key in INT_TYPES and not val_is_an_int: try: - value = int(value) + value = int(value) # type: ignore[arg-type] val_is_an_int = True except (ValueError, TypeError): pass # Set integers that are less than equal to 2^53 as metrics - if val_is_an_int and abs(value) <= 2 ** 53: + if val_is_an_int and abs(value) <= 2 ** 53: # type: ignore[arg-type] self.set_metric(key, value) return @@ -270,18 +279,21 @@ def set_tag(self, key, value=None): log.warning("error setting tag %s, ignoring it", key, exc_info=True) def _set_str_tag(self, key, value): - # (str, str) -> None + # type: (str, str) -> None self.meta[key] = stringify(value) def _remove_tag(self, key): + # type: (str) -> None if key in self.meta: del self.meta[key] def get_tag(self, key): + # type: (str) -> Optional[str] """Return the given tag or None if it doesn't exist.""" return self.meta.get(key, None) def set_tags(self, tags): + # type: (Dict[str, Any]) -> None """Set a dictionary of tags on the given span. Keys and values must be strings (or stringable) """ @@ -290,12 +302,15 @@ def set_tags(self, tags): self.set_tag(k, v) def set_meta(self, k, v): + # type: (str, Any) -> None self.set_tag(k, v) def set_metas(self, kvs): + # type: (Dict[str, Any]) -> None self.set_tags(kvs) def set_metric(self, key, value): + # type: (str, Any) -> None # This method sets a numeric tag value for the given key. It acts # like `set_meta()` and it simply add a tag without further processing. @@ -328,14 +343,17 @@ def set_metric(self, key, value): self.metrics[key] = value def set_metrics(self, metrics): + # type: (Dict[str, Any]) -> None if metrics: for k, v in iteritems(metrics): self.set_metric(k, v) def get_metric(self, key): + # type: (str) -> Any return self.metrics.get(key) def to_dict(self): + # type: () -> Dict[str, Any] d = { "trace_id": self.trace_id, "parent_id": self.parent_id, @@ -360,10 +378,10 @@ def to_dict(self): d["duration"] = self.duration_ns if self.meta: - d["meta"] = self.meta + d["meta"] = self.meta # type: ignore[assignment] if self.metrics: - d["metrics"] = self.metrics + d["metrics"] = self.metrics # type: ignore[assignment] if self.span_type: d["type"] = self.span_type @@ -371,6 +389,7 @@ def to_dict(self): return d def set_traceback(self, limit=20): + # type: (int) -> None """If the current stack has an exception, tag the span with the relevant error info. If not, set the span to the current python stack. """ @@ -383,11 +402,12 @@ def set_traceback(self, limit=20): self.meta[errors.ERROR_STACK] = tb def set_exc_info(self, exc_type, exc_val, exc_tb): + # type: (Any, Any, Any) -> None """ Tag the span with an error tuple as from `sys.exc_info()`. """ if not (exc_type and exc_val and exc_tb): return # nothing to do - if self._ignored_exceptions and any([issubclass(exc_type, e) for e in self._ignored_exceptions]): + if self._ignored_exceptions and any([issubclass(exc_type, e) for e in self._ignored_exceptions]): # type: ignore[arg-type] # noqa return self.error = 1 @@ -405,6 +425,7 @@ def set_exc_info(self, exc_type, exc_val, exc_tb): self.meta[errors.ERROR_STACK] = tb def _remove_exc_info(self): + # type: () -> None """ Remove all exception related information from the span. """ self.error = 0 self._remove_tag(errors.ERROR_MSG) @@ -412,6 +433,7 @@ def _remove_exc_info(self): self._remove_tag(errors.ERROR_STACK) def pprint(self): + # type: () -> str """ Return a human readable version of the span. """ lines = [ ("name", self.name), diff --git a/ddtrace/tracer.py b/ddtrace/tracer.py index 96d3bc322ca..448ddce45ad 100644 --- a/ddtrace/tracer.py +++ b/ddtrace/tracer.py @@ -22,7 +22,6 @@ from .constants import SAMPLE_RATE_METRIC_KEY from .constants import VERSION_KEY from .context import Context -from .ext import SpanTypes from .ext import system from .ext.priority import AUTO_KEEP from .ext.priority import AUTO_REJECT @@ -336,7 +335,7 @@ def start_span( child_of=None, # type: Optional[Union[Span, Context]] service=None, # type: Optional[str] resource=None, # type: Optional[str] - span_type=None, # type: Optional[Union[str, SpanTypes]] + span_type=None, # type: Optional[str] ): # type: (...) -> Span """ @@ -560,7 +559,7 @@ def _log_compat(self, level, msg): self.log.log(level, msg) def trace(self, name, service=None, resource=None, span_type=None): - # type: (str, Optional[str], Optional[str], Optional[Union[str, SpanTypes]]) -> Span + # type: (str, Optional[str], Optional[str], Optional[str]) -> Span """ Return a span that will trace an operation called `name`. The context that created the span as well as the span parenting, are automatically handled by the tracing From f1379cd3fa24fd9956861aa33eaa7a3ac00d6bb0 Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Tue, 16 Mar 2021 15:32:35 -0400 Subject: [PATCH 02/10] Type checked provider, addressed PR comments --- ddtrace/context.py | 11 +++++------ ddtrace/provider.py | 7 ++++++- ddtrace/span.py | 7 ++++++- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/ddtrace/context.py b/ddtrace/context.py index ea7fd3179fe..80adf60a333 100644 --- a/ddtrace/context.py +++ b/ddtrace/context.py @@ -3,10 +3,11 @@ from typing import Optional from typing import Tuple +from ddtrace import Span + from .constants import ORIGIN_KEY from .constants import SAMPLING_PRIORITY_KEY from .internal.logger import get_logger -from .span import Span from .utils.formats import asbool from .utils.formats import get_env @@ -130,16 +131,14 @@ def _set_current_span(self, span): self._parent_span_id = None def add_span(self, span): - # type: (Optional[Span]) -> None + # type: (Span) -> None """ Add a span to the context trace list, keeping it as the last active span. """ with self._lock: self._set_current_span(span) - - # TODO: Check if span is None - self._trace.append(span) # type: ignore - span._context = self # type: ignore + self._trace.append(span) + span._context = self def close_span(self, span): # type: (Span) -> Tuple[Optional[List[Span]], Optional[bool]] diff --git a/ddtrace/provider.py b/ddtrace/provider.py index a556767c104..6446c46e291 100644 --- a/ddtrace/provider.py +++ b/ddtrace/provider.py @@ -25,10 +25,12 @@ def _has_active_context(self): @abc.abstractmethod def activate(self, context): + # type: (Context) -> None pass @abc.abstractmethod def active(self): + # type: () -> Context pass def __call__(self, *args, **kwargs): @@ -46,6 +48,7 @@ class DefaultContextProvider(BaseContextProvider): """ def __init__(self): + # type: () -> None _DD_CONTEXTVAR.set(None) def _has_active_context(self): @@ -59,12 +62,14 @@ def _has_active_context(self): return ctx is not None def activate(self, ctx): + # type: (Context) -> None """Makes the given ``context`` active, so that the provider calls the thread-local storage implementation. """ - _DD_CONTEXTVAR.set(ctx) + _DD_CONTEXTVAR.set(ctx) # type: ignore[arg-type] def active(self): + # type: () -> Context """Returns the current active ``Context`` for this tracer. Returned ``Context`` must be thread-safe or thread-local for this specific implementation. diff --git a/ddtrace/span.py b/ddtrace/span.py index 3de528cf3a2..5da40360baf 100644 --- a/ddtrace/span.py +++ b/ddtrace/span.py @@ -5,6 +5,7 @@ from typing import Dict from typing import List from typing import Optional +from typing import Union from .compat import StringIO from .compat import is_integer @@ -62,7 +63,7 @@ class Span(object): def __init__( self, - tracer, # type: Tracer + tracer, # type: Optional[Tracer] name, # type: str service=None, # type: Optional[str] resource=None, # type: Optional[str] @@ -131,11 +132,13 @@ def _ignore_exception(self, exc): @property def start(self): + # type: () -> float """The start timestamp in Unix epoch seconds.""" return self.start_ns / 1e9 @start.setter def start(self, value): + # type: (Union[int, float]) -> None self.start_ns = int(value * 1e9) @property @@ -148,6 +151,7 @@ def span_type(self, value): @property def finished(self): + # type: () -> bool return self.duration_ns is not None @finished.setter @@ -169,6 +173,7 @@ def duration(self): """The span duration in seconds.""" if self.duration_ns is not None: return self.duration_ns / 1e9 + # TODO: add return None if self.duration_ns is None @duration.setter def duration(self, value): From b508528920a6e4506001c72772b31b1bbe3eb7e6 Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Tue, 16 Mar 2021 16:01:52 -0400 Subject: [PATCH 03/10] Attempt #2 to remove circular dependency --- ddtrace/context.py | 16 ++++++++-------- ddtrace/span.py | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ddtrace/context.py b/ddtrace/context.py index 80adf60a333..39e0cac5303 100644 --- a/ddtrace/context.py +++ b/ddtrace/context.py @@ -3,7 +3,7 @@ from typing import Optional from typing import Tuple -from ddtrace import Span +import ddtrace from .constants import ORIGIN_KEY from .constants import SAMPLING_PRIORITY_KEY @@ -48,9 +48,9 @@ def __init__( :param int trace_id: trace_id of parent span :param int span_id: span_id of parent span """ - self._trace = [] # type: List[Span] + self._trace = [] # type: List[ddtrace.Span] self._finished_spans = 0 - self._current_span = None # type: Optional[Span] + self._current_span = None # type: Optional[ddtrace.Span] self._lock = threading.Lock() self._parent_trace_id = trace_id @@ -99,14 +99,14 @@ def clone(self): return new_ctx def get_current_root_span(self): - # type: () -> Optional[Span] + # type: () -> Optional[ddtrace.Span] """ Return the root span of the context or None if it does not exist. """ return self._trace[0] if len(self._trace) > 0 else None def get_current_span(self): - # type: () -> Optional[Span] + # type: () -> Optional[ddtrace.Span] """ Return the last active span that corresponds to the last inserted item in the trace list. This cannot be considered as the current active @@ -117,7 +117,7 @@ def get_current_span(self): return self._current_span def _set_current_span(self, span): - # type: (Optional[Span]) -> None + # type: (Optional[ddtrace.Span]) -> None """ Set current span internally. @@ -131,7 +131,7 @@ def _set_current_span(self, span): self._parent_span_id = None def add_span(self, span): - # type: (Span) -> None + # type: (ddtrace.Span) -> None """ Add a span to the context trace list, keeping it as the last active span. """ @@ -141,7 +141,7 @@ def add_span(self, span): span._context = self def close_span(self, span): - # type: (Span) -> Tuple[Optional[List[Span]], Optional[bool]] + # type: (ddtrace.Span) -> Tuple[Optional[List[ddtrace.Span]], Optional[bool]] """ Mark a span as a finished, increasing the internal counter to prevent cycles inside _trace list. diff --git a/ddtrace/span.py b/ddtrace/span.py index 5da40360baf..baae604c235 100644 --- a/ddtrace/span.py +++ b/ddtrace/span.py @@ -119,7 +119,7 @@ def __init__( # sampling self.sampled = True # type: bool - self._context = context + self._context = context # type: Optional[Context] self._parent = None # type: Optional[Span] self._ignored_exceptions = None # type: Optional[List[Exception]] From 8ee5d4c59ab6aa7279f04382c095cd36940810ff Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Tue, 16 Mar 2021 16:13:35 -0400 Subject: [PATCH 04/10] Attempt to fix circular import #3 --- ddtrace/context.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/ddtrace/context.py b/ddtrace/context.py index 39e0cac5303..14c6e1cb168 100644 --- a/ddtrace/context.py +++ b/ddtrace/context.py @@ -1,10 +1,9 @@ import threading from typing import List from typing import Optional +from typing import TYPE_CHECKING from typing import Tuple -import ddtrace - from .constants import ORIGIN_KEY from .constants import SAMPLING_PRIORITY_KEY from .internal.logger import get_logger @@ -12,6 +11,9 @@ from .utils.formats import get_env +if TYPE_CHECKING: + from ddtrace import Span + log = get_logger(__name__) @@ -48,9 +50,9 @@ def __init__( :param int trace_id: trace_id of parent span :param int span_id: span_id of parent span """ - self._trace = [] # type: List[ddtrace.Span] + self._trace = [] # type: List[Span] self._finished_spans = 0 - self._current_span = None # type: Optional[ddtrace.Span] + self._current_span = None # type: Optional[Span] self._lock = threading.Lock() self._parent_trace_id = trace_id @@ -99,14 +101,14 @@ def clone(self): return new_ctx def get_current_root_span(self): - # type: () -> Optional[ddtrace.Span] + # type: () -> Optional[Span] """ Return the root span of the context or None if it does not exist. """ return self._trace[0] if len(self._trace) > 0 else None def get_current_span(self): - # type: () -> Optional[ddtrace.Span] + # type: () -> Optional[Span] """ Return the last active span that corresponds to the last inserted item in the trace list. This cannot be considered as the current active @@ -117,7 +119,7 @@ def get_current_span(self): return self._current_span def _set_current_span(self, span): - # type: (Optional[ddtrace.Span]) -> None + # type: (Optional[Span]) -> None """ Set current span internally. @@ -131,7 +133,7 @@ def _set_current_span(self, span): self._parent_span_id = None def add_span(self, span): - # type: (ddtrace.Span) -> None + # type: (Span) -> None """ Add a span to the context trace list, keeping it as the last active span. """ @@ -141,7 +143,7 @@ def add_span(self, span): span._context = self def close_span(self, span): - # type: (ddtrace.Span) -> Tuple[Optional[List[ddtrace.Span]], Optional[bool]] + # type: (Span) -> Tuple[Optional[List[Span]], Optional[bool]] """ Mark a span as a finished, increasing the internal counter to prevent cycles inside _trace list. From ce7ef82331a19874c330f30b2bd3d63a17e26a5f Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Tue, 16 Mar 2021 16:19:33 -0400 Subject: [PATCH 05/10] Attempt to remove circular dependency #4 --- ddtrace/filters.py | 6 +++++- ddtrace/span.py | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/ddtrace/filters.py b/ddtrace/filters.py index 5d674bba8e2..e28f3245643 100644 --- a/ddtrace/filters.py +++ b/ddtrace/filters.py @@ -2,13 +2,17 @@ import re from typing import List from typing import Optional +from typing import TYPE_CHECKING -from ddtrace import Span from ddtrace.vendor import six from .ext import http +if TYPE_CHECKING: + from ddtrace import Span + + class TraceFilter(six.with_metaclass(abc.ABCMeta)): # type: ignore[misc] @abc.abstractmethod def process_trace(self, trace): diff --git a/ddtrace/span.py b/ddtrace/span.py index baae604c235..a568147aa11 100644 --- a/ddtrace/span.py +++ b/ddtrace/span.py @@ -5,6 +5,7 @@ from typing import Dict from typing import List from typing import Optional +from typing import TYPE_CHECKING from typing import Union from .compat import StringIO @@ -20,7 +21,6 @@ from .constants import SERVICE_VERSION_KEY from .constants import SPAN_MEASURED_KEY from .constants import VERSION_KEY -from .context import Context from .ext import SpanTypes from .ext import errors from .ext import http @@ -32,6 +32,10 @@ from .vendor import six +if TYPE_CHECKING: + from .context import Context + + log = get_logger(__name__) From dd8f5eee91bb87c73dce0690df5ffe2cc2a5ce7e Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Tue, 16 Mar 2021 16:23:44 -0400 Subject: [PATCH 06/10] Attempt to remove circular dependency #5 --- ddtrace/internal/writer.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ddtrace/internal/writer.py b/ddtrace/internal/writer.py index 48b4908b4e6..646a0e281e7 100644 --- a/ddtrace/internal/writer.py +++ b/ddtrace/internal/writer.py @@ -6,9 +6,9 @@ import threading from typing import List from typing import Optional +from typing import TYPE_CHECKING import ddtrace -from ddtrace import Span from ddtrace.vendor import six from . import agent @@ -29,6 +29,10 @@ from .sma import SimpleMovingAverage +if TYPE_CHECKING: + from ddtrace import Span + + log = get_logger(__name__) DEFAULT_SHUTDOWN_TIMEOUT = 5 From 775c626b381683d6670bf1a17d784bdb7e0006dd Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Tue, 16 Mar 2021 16:30:35 -0400 Subject: [PATCH 07/10] Attempt 6 to remove circular dependency --- ddtrace/helpers.py | 6 +++++- ddtrace/provider.py | 6 +++++- ddtrace/span.py | 2 +- ddtrace/tracer.py | 8 ++++++-- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/ddtrace/helpers.py b/ddtrace/helpers.py index aa2c182fb74..409c1ab9819 100644 --- a/ddtrace/helpers.py +++ b/ddtrace/helpers.py @@ -1,8 +1,12 @@ from typing import Optional +from typing import TYPE_CHECKING from typing import Tuple import ddtrace -from ddtrace.tracer import Tracer + + +if TYPE_CHECKING: + from ddtrace.tracer import Tracer def get_correlation_ids(tracer=None): diff --git a/ddtrace/provider.py b/ddtrace/provider.py index 6446c46e291..c8ce9b81a3a 100644 --- a/ddtrace/provider.py +++ b/ddtrace/provider.py @@ -1,9 +1,13 @@ import abc +from typing import TYPE_CHECKING from ddtrace.vendor import six from .compat import contextvars -from .context import Context + + +if TYPE_CHECKING: + from .context import Context _DD_CONTEXTVAR = contextvars.ContextVar("datadog_contextvar", default=None) diff --git a/ddtrace/span.py b/ddtrace/span.py index a568147aa11..39cc3121fc5 100644 --- a/ddtrace/span.py +++ b/ddtrace/span.py @@ -28,12 +28,12 @@ from .ext import priority from .internal import _rand from .internal.logger import get_logger -from .tracer import Tracer from .vendor import six if TYPE_CHECKING: from .context import Context + from .tracer import Tracer log = get_logger(__name__) diff --git a/ddtrace/tracer.py b/ddtrace/tracer.py index 448ddce45ad..da71448f32c 100644 --- a/ddtrace/tracer.py +++ b/ddtrace/tracer.py @@ -10,6 +10,7 @@ from typing import List from typing import Optional from typing import Set +from typing import TYPE_CHECKING from typing import Union from ddtrace import config @@ -21,7 +22,6 @@ from .constants import HOSTNAME_KEY from .constants import SAMPLE_RATE_METRIC_KEY from .constants import VERSION_KEY -from .context import Context from .ext import system from .ext.priority import AUTO_KEEP from .ext.priority import AUTO_REJECT @@ -44,12 +44,16 @@ from .sampler import DatadogSampler from .sampler import RateByServiceSampler from .sampler import RateSampler -from .span import Span from .utils.deprecation import deprecated from .utils.formats import asbool from .utils.formats import get_env +if TYPE_CHECKING: + from .context import Context + from .span import Span + + log = get_logger(__name__) debug_mode = asbool(get_env("trace", "debug", default=False)) From 205bb2b3c65fe951e06f07b8b65ab38b29da1fdf Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Tue, 16 Mar 2021 16:36:51 -0400 Subject: [PATCH 08/10] Revert type checking check in provider.py --- ddtrace/provider.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ddtrace/provider.py b/ddtrace/provider.py index c8ce9b81a3a..6446c46e291 100644 --- a/ddtrace/provider.py +++ b/ddtrace/provider.py @@ -1,13 +1,9 @@ import abc -from typing import TYPE_CHECKING from ddtrace.vendor import six from .compat import contextvars - - -if TYPE_CHECKING: - from .context import Context +from .context import Context _DD_CONTEXTVAR = contextvars.ContextVar("datadog_contextvar", default=None) From ceb70164f3c9b24eef77f99eace22039c22920ff Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Tue, 16 Mar 2021 16:42:51 -0400 Subject: [PATCH 09/10] Reverted type check checking for tracer.py --- ddtrace/tracer.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ddtrace/tracer.py b/ddtrace/tracer.py index da71448f32c..448ddce45ad 100644 --- a/ddtrace/tracer.py +++ b/ddtrace/tracer.py @@ -10,7 +10,6 @@ from typing import List from typing import Optional from typing import Set -from typing import TYPE_CHECKING from typing import Union from ddtrace import config @@ -22,6 +21,7 @@ from .constants import HOSTNAME_KEY from .constants import SAMPLE_RATE_METRIC_KEY from .constants import VERSION_KEY +from .context import Context from .ext import system from .ext.priority import AUTO_KEEP from .ext.priority import AUTO_REJECT @@ -44,16 +44,12 @@ from .sampler import DatadogSampler from .sampler import RateByServiceSampler from .sampler import RateSampler +from .span import Span from .utils.deprecation import deprecated from .utils.formats import asbool from .utils.formats import get_env -if TYPE_CHECKING: - from .context import Context - from .span import Span - - log = get_logger(__name__) debug_mode = asbool(get_env("trace", "debug", default=False)) From f87e4eab567d7537fa94cae745a6edcb93e0fbfb Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Tue, 16 Mar 2021 17:09:20 -0400 Subject: [PATCH 10/10] Changed mistaken int arg type to float in span.duration setter --- ddtrace/span.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddtrace/span.py b/ddtrace/span.py index 624b51a2b16..0392897f9ac 100644 --- a/ddtrace/span.py +++ b/ddtrace/span.py @@ -181,7 +181,7 @@ def duration(self): @duration.setter def duration(self, value): - # type: (int) -> None + # type: (float) -> None self.duration_ns = int(value * 1e9) def finish(self, finish_time=None):