Skip to content

Commit

Permalink
Merge pull request #32 from savannahghi/develop
Browse files Browse the repository at this point in the history
release v1.3.0
  • Loading branch information
kennedykori committed Mar 31, 2024
2 parents e483694 + c79e35e commit a44d384
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 6 deletions.
6 changes: 5 additions & 1 deletion .releaserc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ presetConfig:
- type: release
hidden: true
- type: test
section: hidden
hidden: true
releaseRules:
- type: chore
scope: deps
Expand All @@ -86,5 +86,9 @@ releaseRules:
release: minor
- type: fix
release: patch
- scope: minor
release: minor
- scope: patch
release: patch
- scope: no-release
release: false
13 changes: 13 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
## [1.3.0-rc.1](https://github.com/savannahghi/sghi-commons/compare/v1.2.0...v1.3.0-rc.1) (2024-03-31)


### Features

* **checkers:** add a checker for callable objects ([#29](https://github.com/savannahghi/sghi-commons/issues/29)) ([0f8272d](https://github.com/savannahghi/sghi-commons/commit/0f8272de6f9ad13809599666ef8b78a34aab9853))


### Refactors

* **patch:** explicitly list `sghi.retry` module exports ([#28](https://github.com/savannahghi/sghi-commons/issues/28)) ([45cd87e](https://github.com/savannahghi/sghi-commons/commit/45cd87e7cf956d01a8ef12aef42dbd49dc3b8508))
* refactor retry to use `ensure_callable` ([#30](https://github.com/savannahghi/sghi-commons/issues/30)) ([51511c8](https://github.com/savannahghi/sghi-commons/commit/51511c83eec7632bccc5f60e7eaf47f17dce9bf9))

## [1.2.0](https://github.com/savannahghi/sghi-commons/compare/v1.1.0...v1.2.0) (2024-03-30)


Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sghi-commons",
"version": "1.2.0",
"version": "1.3.0-rc.1",
"description": "Collection of utilities and reusable components used throughout our Python projects.",
"directories": {
"doc": "docs"
Expand Down
21 changes: 17 additions & 4 deletions src/sghi/retry/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@

from sghi.exceptions import SGHIError, SGHITransientError
from sghi.utils import (
ensure_callable,
ensure_greater_or_equal,
ensure_greater_than,
ensure_predicate,
type_fqn,
)

Expand Down Expand Up @@ -289,11 +289,10 @@ def __init__(
timeout: float | None = _DEFAULT_TIMEOUT,
multiplicative_factor: float = _DEFAULT_MULTIPLICATIVE_FACTOR,
) -> None:
ensure_predicate(
callable(predicate),
self._predicate: _RetryPredicate = ensure_callable(
value=predicate,
message="'predicate' MUST be a callable.",
)
self._predicate: _RetryPredicate = predicate
self._initial_delay: float = ensure_greater_than(
value=initial_delay,
base_value=0.0,
Expand Down Expand Up @@ -436,3 +435,17 @@ def retry(self, f: Callable[_P, _RT]) -> Callable[_P, _RT]:
exponential_backoff_retry = Retry.of_exponential_backoff

noop_retry = Retry.of_noop


# =============================================================================
# MODULE EXPORTS
# =============================================================================

__all__ = [
"Retry",
"RetryError",
"exponential_backoff_retry",
"if_exception_type_factory",
"if_transient_exception",
"noop_retry",
]
2 changes: 2 additions & 0 deletions src/sghi/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Common utilities used throughout SGHI projects."""

from .checkers import (
ensure_callable,
ensure_greater_or_equal,
ensure_greater_than,
ensure_instance_of,
Expand All @@ -15,6 +16,7 @@
from .others import future_succeeded, type_fqn

__all__ = [
"ensure_callable",
"ensure_greater_or_equal",
"ensure_greater_than",
"ensure_instance_of",
Expand Down
23 changes: 23 additions & 0 deletions src/sghi/utils/checkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,29 @@
# =============================================================================


def ensure_callable(value: _T, message: str = "A callable is required.") -> _T:
"""Check that the given value is a callable object (some kind of function).
A callable should have the same semantics as those defined by the
``builtin.callable`` function to qualify. That is, it should be function or
method, a class or an instance of a class with a ``__call__`` method.
If ``value`` is NOT a callable, then a :exc:`ValueError` is raised; else
``value`` is returned as is.
:param value: The object to check if it is a callable.
:param message: An optional error message to be shown when ``value`` is NOT
a callable.
:return: ``value`` if it is a callable.
:raise ValueError: If the given ``value`` is NOT a callable.
"""
if not callable(value):
raise ValueError(message)
return value


def ensure_greater_or_equal(
value: _CT,
base_value: Comparable,
Expand Down
42 changes: 42 additions & 0 deletions test/sghi/utils_tests/checkers_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import sghi.app
from sghi.config import Config, ConfigProxy
from sghi.utils import (
ensure_callable,
ensure_greater_or_equal,
ensure_greater_than,
ensure_instance_of,
Expand All @@ -23,6 +24,47 @@
from sghi.typing import Comparable


def test_ensure_callable_return_value_on_valid_input() -> None:
"""
:func:`ensure_callable` should return the input value if the given
``value`` is a callable.
"""

class _Callable:
def __call__(self, *args, **kwargs) -> None: ...

a_callable = _Callable()

assert ensure_callable(callable) is callable
assert ensure_callable(type_fqn) is type_fqn
assert ensure_callable(_Callable) is _Callable
assert ensure_callable(a_callable) is a_callable


def test_ensure_callable_fails_on_invalid_input() -> None:
"""
:func:`ensure_callable` should raise a ``ValueError`` when the given
``value`` is not a callable.
"""
inputs: Iterable = ("", 45, None, [])

# With default message
default_msg: str = "A callable is required."
for value in inputs:
with pytest.raises(ValueError, match=default_msg) as exp_info:
ensure_callable(value)

assert exp_info.value.args[0] == default_msg

# Test with a custom message
custom_msg: str = "Would you please provide a callable."
for value in inputs:
with pytest.raises(ValueError, match=custom_msg) as exp_info:
ensure_callable(value, message=custom_msg)

assert exp_info.value.args[0] == custom_msg


def test_ensure_greater_or_equal_return_value_on_valid_input() -> None:
"""
:func:`ensure_greater_or_equal` should return the input value if the given
Expand Down

0 comments on commit a44d384

Please sign in to comment.