Skip to content

Commit

Permalink
Split it up. (facebook#366)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: facebook#366

Split up testslide into 3 separate libraries
- core to house the core functionality around mocking
- dsl contains the testslide dsl
- executor has the runner and import profiler

Differential Revision: D55324794
  • Loading branch information
deathowl authored and facebook-github-bot committed Mar 28, 2024
1 parent f22c183 commit e5dd6f2
Show file tree
Hide file tree
Showing 17 changed files with 1,259 additions and 1,174 deletions.
1,034 changes: 21 additions & 1,013 deletions testslide/__init__.py

Large diffs are not rendered by default.

76 changes: 76 additions & 0 deletions testslide/core/__init__.py
@@ -0,0 +1,76 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

import os

if "COVERAGE_PROCESS_START" in os.environ:
import coverage

coverage.process_startup()

import os
import sys
import unittest

from typing import Any

from . import mock_callable as _mock_callable, mock_constructor as _mock_constructor, patch_attribute as _patch_attribute
from .strict_mock import StrictMock # noqa

if sys.version_info < (3, 7):
raise RuntimeError("Python >=3.7 required.")

def _importer(target: str) -> Any:
components = target.split(".")
import_path = components.pop(0)
thing = __import__(import_path)

def dot_lookup(thing: object, comp: str, import_path: str) -> Any:
try:
return getattr(thing, comp)
except AttributeError:
__import__(import_path)
return getattr(thing, comp)

for comp in components:
import_path += ".%s" % comp
thing = dot_lookup(thing, comp, import_path)
return thing

class TestCase(unittest.TestCase):
"""
A subclass of unittest.TestCase that adds TestSlide's features.
"""

def setUp(self) -> None:
_mock_callable.register_assertion = lambda assertion: self.addCleanup(
assertion
)
self.addCleanup(_mock_callable.unpatch_all_callable_mocks)
self.addCleanup(_mock_constructor.unpatch_all_constructor_mocks)
self.addCleanup(_patch_attribute.unpatch_all_mocked_attributes)
super(TestCase, self).setUp()

@staticmethod
def mock_callable(
*args: Any, **kwargs: Any
) -> _mock_callable._MockCallableDSL:
return _mock_callable.mock_callable(*args, **kwargs)

@staticmethod
def mock_async_callable(
*args: Any, **kwargs: Any
) -> _mock_callable._MockCallableDSL:
return _mock_callable.mock_async_callable(*args, **kwargs)

@staticmethod
def mock_constructor(
*args: Any, **kwargs: Any
) -> _mock_constructor._MockConstructorDSL:
return _mock_constructor.mock_constructor(*args, **kwargs)

@staticmethod
def patch_attribute(*args: Any, **kwargs: Any) -> None:
return _patch_attribute.patch_attribute(*args, **kwargs)
4 changes: 2 additions & 2 deletions testslide/lib.py → testslide/core/lib.py
Expand Up @@ -50,8 +50,8 @@ def get_args(tp):

if TYPE_CHECKING:
# hack to remove mypy warnings about types not being defined
from testslide.mock_callable import _CallableMock
from testslide.strict_mock import StrictMock, _DefaultMagic
from testslide.core.mock_callable import _CallableMock
from testslide.core.strict_mock import StrictMock, _DefaultMagic

##
## Type validation
Expand Down
File renamed without changes.
Expand Up @@ -22,15 +22,15 @@
)
from unittest.mock import Mock

from testslide.lib import _validate_return_type, _wrap_signature_and_type_validation
from testslide.strict_mock import StrictMock
from testslide.core.lib import _validate_return_type, _wrap_signature_and_type_validation
from testslide.core.strict_mock import StrictMock

from .lib import CoroutineValueError, _bail_if_private, _is_a_builtin
from .patch import _is_instance_method, _patch

if TYPE_CHECKING:
from testslide.matchers import RegexMatches # noqa: F401
from testslide.mock_constructor import _MockConstructorDSL # noqa: F401
from .matchers import RegexMatches # noqa: F401
from .mock_constructor import _MockConstructorDSL # noqa: F401


def mock_callable(
Expand Down
Expand Up @@ -5,7 +5,7 @@
import inspect
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union

from testslide.mock_callable import _CallableMock, _MockCallableDSL
from testslide.core.mock_callable import _CallableMock, _MockCallableDSL

from .lib import (
_bail_if_private,
Expand Down
File renamed without changes.
Expand Up @@ -5,7 +5,7 @@

from typing import Any, Callable, Dict, Tuple

from testslide.strict_mock import StrictMock, UndefinedAttribute
from testslide.core.strict_mock import StrictMock, UndefinedAttribute

from .lib import _bail_if_private, _validate_argument_type
from .patch import _patch
Expand Down
24 changes: 11 additions & 13 deletions testslide/strict_mock.py → testslide/core/strict_mock.py
Expand Up @@ -19,12 +19,10 @@
get_type_hints,
)

import testslide.lib
import testslide.mock_callable

from . import lib, mock_callable
if TYPE_CHECKING:
# Hack to enable typing information for mypy
from testslide.mock_callable import _CallableMock, _YieldValuesRunner # noqa: F401
from testslide.core.mock_callable import _CallableMock, _YieldValuesRunner # noqa: F401


class UndefinedAttribute(BaseException):
Expand Down Expand Up @@ -694,7 +692,7 @@ def __validate_attribute_type(self, name: str, value: Any) -> None:
# Some modules can throw KeyError : https://bugs.python.org/issue41515
annotations = {}
if name in annotations:
testslide.lib._validate_argument_type(annotations[name], name, value)
lib._validate_argument_type(annotations[name], name, value)

def __validate_and_wrap_mock_value(self, name: str, value: Any) -> Any:
if self._template:
Expand All @@ -714,7 +712,7 @@ def __validate_and_wrap_mock_value(self, name: str, value: Any) -> Any:
raise NonCallableValue(self, name)
if self.__dict__["_type_validation"]:
signature_validation_wrapper = (
testslide.lib._wrap_signature_and_type_validation(
lib._wrap_signature_and_type_validation(
value,
self._template,
name,
Expand All @@ -734,7 +732,7 @@ async def awaitable_return_validation_wrapper(
raise NonAwaitableReturn(self, name)

return_value = await result_awaitable
if not testslide.lib._is_wrapped_for_signature_and_type_validation(
if not lib._is_wrapped_for_signature_and_type_validation(
# The original value was already wrapped for type
# validation. Skipping additional validation to
# allow, for example, mock_callable to disable
Expand All @@ -745,9 +743,9 @@ async def awaitable_return_validation_wrapper(
# If the return value is a _BaseRunner then type
# validation, if needed, has already been performed
return_value,
testslide.mock_callable._BaseRunner,
mock_callable._BaseRunner,
):
testslide.lib._validate_return_type(
lib._validate_return_type(
template_value,
return_value,
self.__dict__["_caller_frame_info"],
Expand All @@ -761,7 +759,7 @@ def return_validation_wrapper(*args, **kwargs):
return_value = signature_validation_wrapper(
*args, **kwargs
)
if not testslide.lib._is_wrapped_for_signature_and_type_validation(
if not lib._is_wrapped_for_signature_and_type_validation(
# The original value was already wrapped for type
# validation. Skipping additional validation to
# allow, for example, mock_callable to disable
Expand All @@ -772,9 +770,9 @@ def return_validation_wrapper(*args, **kwargs):
# If the return value is a _BaseRunner then type
# validation, if needed, has already been performed
return_value,
testslide.mock_callable._BaseRunner,
mock_callable._BaseRunner,
):
testslide.lib._validate_return_type(
lib._validate_return_type(
template_value,
return_value,
self.__dict__["_caller_frame_info"],
Expand Down Expand Up @@ -901,4 +899,4 @@ def _extract_StrictMock_template(mock_obj: StrictMock) -> Optional[Any]:
return None


testslide.lib.MOCK_TEMPLATE_EXTRACTORS[StrictMock] = _extract_StrictMock_template # type: ignore
lib.MOCK_TEMPLATE_EXTRACTORS[StrictMock] = _extract_StrictMock_template # type: ignore
7 changes: 3 additions & 4 deletions testslide/dsl.py → testslide/dsl/dsl.py
Expand Up @@ -9,10 +9,9 @@
from re import sub as _sub
from typing import Any, Callable, NoReturn, Optional, Union

from testslide import Context, TestCase
from testslide.core import TestCase

from . import Context as _Context
from . import Skip # noqa: F401
from .lib import Context, Skip # noqa: F401

ExampleFunction = Callable[..., Any]
HaltingFunction = Callable[..., NoReturn]
Expand Down Expand Up @@ -76,7 +75,7 @@ def _create_context(
self, name: str, context_code: ExampleFunction, *args: Any, **kwargs: Any
) -> HaltingFunction:
if not self.current_context:
new_context = _Context(name, skip=self.skip, focus=self.focus)
new_context = Context(name, skip=self.skip, focus=self.focus)
else:
new_context = self.current_context.add_child_context(
name, skip=self.skip, focus=self.focus
Expand Down

0 comments on commit e5dd6f2

Please sign in to comment.