From 402b309dd77592d110216c96f7209fc50222dfba Mon Sep 17 00:00:00 2001 From: Aliaksei Urbanski Date: Wed, 21 Aug 2019 01:58:54 +0300 Subject: [PATCH] Fix and improve tests I believe it would be nice to have tests on CI not only for Python 3.7, but for all supported Python versions. These changes: - fix test_span_members test - fix compatibility with Python 3.5 and 3.4 - add tests for various Python version on CI - allow running tests for any branches --- .travis.yml | 15 ++++++++--- .../tests/test_wsgi_middleware.py | 6 +++-- .../src/opentelemetry/context/__init__.py | 4 ++- .../opentelemetry/context/async_context.py | 9 ++++--- .../src/opentelemetry/context/base_context.py | 4 +-- .../context/thread_local_context.py | 9 ++++--- opentelemetry-api/src/opentelemetry/loader.py | 2 +- .../src/opentelemetry/trace/__init__.py | 27 ++++++++++--------- opentelemetry-sdk/tests/trace/test_trace.py | 3 +-- tox.ini | 6 +++-- 10 files changed, 51 insertions(+), 34 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4f9cb871ea1..33a51490301 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,14 +3,21 @@ dist: xenial language: python python: + - '3.4' + - '3.5' + - '3.6' - '3.7' + - 'pypy3.5' + - '3.8-dev' + - 'nightly' + +matrix: + allow_failures: + - python: '3.8-dev' + - python: 'nightly' install: - pip install tox-travis script: - tox - -branches: - only: - - master diff --git a/ext/opentelemetry-ext-wsgi/tests/test_wsgi_middleware.py b/ext/opentelemetry-ext-wsgi/tests/test_wsgi_middleware.py index 70b7e8fcf63..0e86a871f45 100644 --- a/ext/opentelemetry-ext-wsgi/tests/test_wsgi_middleware.py +++ b/ext/opentelemetry-ext-wsgi/tests/test_wsgi_middleware.py @@ -94,7 +94,7 @@ def tearDown(self): def start_response(self, status, response_headers, exc_info=None): # The span should have started already - self.span_context_manager.__enter__.assert_called() + self.span_context_manager.__enter__.assert_called_with() self.status = status self.response_headers = response_headers @@ -108,7 +108,9 @@ def validate_response(self, response, error=None): self.span_context_manager.__exit__.assert_not_called() self.assertEqual(value, b"*") except StopIteration: - self.span_context_manager.__exit__.assert_called() + self.span_context_manager.__exit__.assert_called_with( + None, None, None + ) break self.assertEqual(self.status, "200 OK") diff --git a/opentelemetry-api/src/opentelemetry/context/__init__.py b/opentelemetry-api/src/opentelemetry/context/__init__.py index 4edbf2bd048..1495f8828e3 100644 --- a/opentelemetry-api/src/opentelemetry/context/__init__.py +++ b/opentelemetry-api/src/opentelemetry/context/__init__.py @@ -145,7 +145,9 @@ async def main(): __all__ = ['Context'] -Context: typing.Optional[BaseRuntimeContext] +Context = ( # pylint: disable=invalid-name + None +) # type: typing.Optional[BaseRuntimeContext] try: from .async_context import AsyncRuntimeContext diff --git a/opentelemetry-api/src/opentelemetry/context/async_context.py b/opentelemetry-api/src/opentelemetry/context/async_context.py index 413e7b2543f..559d36234be 100644 --- a/opentelemetry-api/src/opentelemetry/context/async_context.py +++ b/opentelemetry-api/src/opentelemetry/context/async_context.py @@ -13,7 +13,7 @@ # limitations under the License. from contextvars import ContextVar -import typing +import typing # pylint: disable=unused-import from . import base_context @@ -23,9 +23,10 @@ class Slot(base_context.BaseRuntimeContext.Slot): def __init__(self, name: str, default: 'object'): # pylint: disable=super-init-not-called self.name = name - self.contextvar: 'ContextVar[object]' = ContextVar(name) - self.default: typing.Callable[..., object] - self.default = base_context.wrap_callable(default) + self.contextvar = ContextVar(name) # type: ContextVar[object] + self.default = base_context.wrap_callable( + default + ) # type: typing.Callable[..., object] def clear(self) -> None: self.contextvar.set(self.default()) diff --git a/opentelemetry-api/src/opentelemetry/context/base_context.py b/opentelemetry-api/src/opentelemetry/context/base_context.py index c750d993ad1..5c1ffb4a8e4 100644 --- a/opentelemetry-api/src/opentelemetry/context/base_context.py +++ b/opentelemetry-api/src/opentelemetry/context/base_context.py @@ -37,7 +37,7 @@ def set(self, value: 'object') -> None: raise NotImplementedError _lock = threading.Lock() - _slots: typing.Dict[str, 'BaseRuntimeContext.Slot'] = {} + _slots = {} # type: typing.Dict[str, 'BaseRuntimeContext.Slot'] @classmethod def clear(cls) -> None: @@ -112,7 +112,7 @@ def with_current_context( def call_with_current_context( *args: 'object', - **kwargs: 'object', + **kwargs: 'object' ) -> 'object': try: backup_context = self.snapshot() diff --git a/opentelemetry-api/src/opentelemetry/context/thread_local_context.py b/opentelemetry-api/src/opentelemetry/context/thread_local_context.py index dd11128b7ac..8313fb57e89 100644 --- a/opentelemetry-api/src/opentelemetry/context/thread_local_context.py +++ b/opentelemetry-api/src/opentelemetry/context/thread_local_context.py @@ -13,7 +13,7 @@ # limitations under the License. import threading -import typing +import typing # pylint: disable=unused-import from . import base_context @@ -25,15 +25,16 @@ class Slot(base_context.BaseRuntimeContext.Slot): def __init__(self, name: str, default: 'object'): # pylint: disable=super-init-not-called self.name = name - self.default: typing.Callable[..., object] - self.default = base_context.wrap_callable(default) + self.default = base_context.wrap_callable( + default + ) # type: typing.Callable[..., object] def clear(self) -> None: setattr(self._thread_local, self.name, self.default()) def get(self) -> 'object': try: - got: object = getattr(self._thread_local, self.name) + got = getattr(self._thread_local, self.name) # type: object return got except AttributeError: value = self.default() diff --git a/opentelemetry-api/src/opentelemetry/loader.py b/opentelemetry-api/src/opentelemetry/loader.py index 9e28846b8c5..78b7cc4f321 100644 --- a/opentelemetry-api/src/opentelemetry/loader.py +++ b/opentelemetry-api/src/opentelemetry/loader.py @@ -83,7 +83,7 @@ def my_factory_for_t(api_type: typing.Type[T]) -> typing.Optional[T]: # code. # ImplementationFactory = Callable[[Type[_T]], Optional[_T]] -_DEFAULT_FACTORY: Optional[_UntrustedImplFactory[object]] = None +_DEFAULT_FACTORY = None # type: Optional[_UntrustedImplFactory[object]] def _try_load_impl_from_modname( diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index aed421307ee..3d07ed3ab8b 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -62,13 +62,18 @@ """ from contextlib import contextmanager -import typing +from typing import Callable +from typing import Dict +from typing import Iterator +from typing import Optional +from typing import Type +from typing import Union from opentelemetry import loader from opentelemetry import types # TODO: quarantine -ParentSpan = typing.Optional[typing.Union['Span', 'SpanContext']] +ParentSpan = Optional[Union['Span', 'SpanContext']] class Span: @@ -155,7 +160,7 @@ def get_default(cls) -> 'TraceOptions': DEFAULT_TRACE_OPTIONS = TraceOptions.get_default() -class TraceState(typing.Dict[str, str]): +class TraceState(Dict[str, str]): """A list of key-value pairs representing vendor-specific trace info. Keys and values are strings of up to 256 printable US-ASCII characters. @@ -278,7 +283,7 @@ def get_current_span(self) -> 'Span': def start_span(self, name: str, parent: ParentSpan = CURRENT_SPAN - ) -> typing.Iterator['Span']: + ) -> Iterator['Span']: """Context manager for span creation. Create a new span. Start the span and set it as the current span in @@ -362,7 +367,7 @@ def create_span(self, return INVALID_SPAN @contextmanager # type: ignore - def use_span(self, span: 'Span') -> typing.Iterator[None]: + def use_span(self, span: 'Span') -> Iterator[None]: """Context manager for controlling a span's lifetime. Start the given span and set it as the current span in this tracer's @@ -378,9 +383,10 @@ def use_span(self, span: 'Span') -> typing.Iterator[None]: yield -_TRACER: typing.Optional[Tracer] = None -_TRACER_FACTORY: typing.Optional[ - typing.Callable[[typing.Type[Tracer]], typing.Optional[Tracer]]] = None +FactoryType = Callable[[Type[Tracer]], Optional[Tracer]] + +_TRACER = None # type: Optional[Tracer] +_TRACER_FACTORY = None # type: Optional[FactoryType] def tracer() -> Tracer: @@ -398,10 +404,7 @@ def tracer() -> Tracer: return _TRACER -def set_preferred_tracer_implementation( - factory: typing.Callable[ - [typing.Type[Tracer]], typing.Optional[Tracer]] - ) -> None: +def set_preferred_tracer_implementation(factory: FactoryType) -> None: """Set the factory to be used to create the tracer. See :mod:`opentelemetry.loader` for details. diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index cf7ca21f137..cd13d0fb70e 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -112,8 +112,7 @@ def test_start_span_explicit(self): self.assertIsNotNone(child.end_time) def test_span_members(self): - context = contextvars.ContextVar('test_span_members') - tracer = trace.Tracer(context) + tracer = trace.Tracer('test_span_members') other_context1 = trace_api.SpanContext( trace_id=trace.generate_trace_id(), diff --git a/tox.ini b/tox.ini index 82178115c09..3ff7731ac0a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,8 +1,9 @@ [tox] skipsdist = True +skip_missing_interpreters = True envlist = - py{34,35,36,37}-test-{api,sdk} - py{34,35,36,37}-test-ext-wsgi + py3{4,5,6,7,8}-test-{api,sdk,ext-wsgi} + pypy35-test-{api,sdk,ext-wsgi} lint py37-mypy docs @@ -24,6 +25,7 @@ changedir = test-ext-wsgi: ext/opentelemetry-ext-wsgi/tests commands_pre = + pip install -U pip setuptools test: pip install -e {toxinidir}/opentelemetry-api test-sdk: pip install -e {toxinidir}/opentelemetry-sdk ext: pip install -e {toxinidir}/opentelemetry-api