Skip to content

Commit

Permalink
Added strict typing
Browse files Browse the repository at this point in the history
  • Loading branch information
akadlec committed Nov 22, 2021
1 parent 4b34bef commit 83be412
Show file tree
Hide file tree
Showing 15 changed files with 123 additions and 55 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -295,16 +295,17 @@ jobs:

strategy:
matrix:
python: ["3.9"]
operating-system: ["ubuntu-latest"]

steps:
- name: "Checkout"
uses: "actions/checkout@v2"

- name: "Set up Python 3.7"
- name: "Set up Python ${{ matrix.python }}"
uses: "actions/setup-python@v1"
with:
python-version: 3.7
python-version: ${{ matrix.python }}

- name: "Extract version"
uses: "battila7/get-version-action@v2"
Expand Down
9 changes: 9 additions & 0 deletions .mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[mypy]
disallow_untyped_defs = True
disallow_any_unimported = True
no_implicit_optional = True
check_untyped_defs = True
warn_return_any = True
show_error_codes = True
warn_unused_ignores = True
mypy_path = tests/stubs
24 changes: 22 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,31 @@ php_coverage: vendor
pylint:
python -m pip install pylint

python_qa: pylint
mypy:
python -m pip install mypy

black:
python -m pip install black

isort:
python -m pip install isort

python_qa: python_cs python_types python_isort python_black

python_cs: pylint
pylint **/*.py

python_types: mypy
mypy **/*.py

python_isort: isort
isort **/*.py --check

python_black: black
black **/*.py --check

python_tests:
python -m unittest

python_coverage:
coverage run --source=redisdb_exchange_plugin -m unittest
coverage run --source=redisdb_exchange_plugin -m unittest
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
[![Python latest stable](https://badgen.net/pypi/v/fastybird-redisdb-exchange-plugin?cache=300&style=flat-square)](https://pypi.org/project/fastybird-redisdb-exchange-plugin/)
[![Python downloads month](https://img.shields.io/pypi/dm/fastybird-redisdb-exchange-plugin?cache=300&style=flat-square)](https://pypi.org/project/fastybird-redisdb-exchange-plugin/)
[![Black](https://img.shields.io/badge/black-enabled-brightgreen.svg?style=flat-square)](https://github.com/psf/black)
[![MyPy](https://img.shields.io/badge/mypy-enabled-brightgreen.svg?style=flat-square)](http://mypy-lang.org)

## What is FastyBird Redis DB exchange plugin?

Expand Down
6 changes: 6 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[tool.black]
line-length = 120

[tool.isort]
profile = "black"
multi_line_output = 3
18 changes: 11 additions & 7 deletions redisdb_exchange_plugin/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@

# pylint: disable=no-value-for-parameter

# Library dependencies
# Python base dependencies
import logging
from typing import Dict, Union

# Library dependencies
from exchange_plugin.publisher import Publisher as ExchangePublisher
from kink import di

Expand All @@ -42,19 +44,21 @@ def create_container(
di["fb-redisdb-exchange-plugin_logger"] = di[Logger]

di[RedisClient] = RedisClient(
host=settings.get("host", "127.0.0.1"),
port=int(settings.get("port", 6379)),
channel_name=settings.get("channel_name", "fb_exchange"),
username=settings.get("username", None),
password=settings.get("password", None),
host=str(settings.get("host", "127.0.0.1")) if settings.get("host", None) is not None else "127.0.0.1",
port=int(str(settings.get("port", 6379))),
channel_name=str(settings.get("channel_name", "fb_exchange"))
if settings.get("channel_name", None) is not None
else "fb_exchange",
username=str(settings.get("username", None)) if settings.get("username", None) is not None else None,
password=str(settings.get("password", None)) if settings.get("password", None) is not None else None,
logger=di[Logger],
)
di["fb-redisdb-exchange-plugin_redis-client"] = di[RedisClient]

di[Publisher] = Publisher(redis_client=di[RedisClient])
di["fb-redisdb-exchange-plugin_publisher"] = di[Publisher]

di[RedisExchange] = RedisExchange(redis_client=di[RedisClient], logger=di[Logger])
di[RedisExchange] = RedisExchange(redis_client=di[RedisClient], logger=di[Logger]) # type: ignore[call-arg]
di["fb-redisdb-exchange-plugin_exchange"] = di[RedisExchange]

di[ExchangePublisher].register_publisher(di[Publisher])
37 changes: 19 additions & 18 deletions redisdb_exchange_plugin/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
Redis DB exchange plugin connection service
"""

# Library dependencies
# Python base dependencies
import json
import uuid
from typing import Dict, Optional, Union

# Library dependencies
from modules_metadata.routing import RoutingKey
from modules_metadata.types import ModuleOrigin
from redis import Redis
Expand All @@ -41,6 +43,7 @@ class RedisClient:
@author Adam Kadlec <adam.kadlec@fastybird.com>
"""

__redis_client: Redis

__pub_sub: Optional[PubSub] = None
Expand Down Expand Up @@ -89,7 +92,7 @@ def publish(self, origin: ModuleOrigin, routing_key: RoutingKey, data: Optional[
self.__logger.debug(
"Successfully published message to: %d consumers via RedisDB exchange plugin with key: %s",
result,
routing_key
routing_key,
)

# -----------------------------------------------------------------------------
Expand Down Expand Up @@ -130,30 +133,28 @@ def unsubscribe(self) -> None:

def receive(self) -> Optional[Dict]:
"""Try to receive new message from exchange"""
result = self.__pub_sub.get_message()
if self.__pub_sub is not None:
result = self.__pub_sub.get_message()

if (
if (
result is not None
and result.get("type") == "message"
and isinstance(result.get("data", bytes("{}", "utf-8")), bytes)
):
message = result.get("data", bytes("{}", "utf-8"))
message = message.decode("utf-8")
):
message_data = result.get("data", bytes("{}", "utf-8"))
message = message_data.decode("utf-8") if isinstance(message_data, bytes) else ""

try:
data: Dict[str, Union[str, int, float, bool, None]] = json.loads(message)
try:
data: Dict[str, Union[str, int, float, bool, None]] = json.loads(message)

# Ignore own messages
if (
data.get("sender_id", None) is not None
and data.get("sender_id", None) == self.__identifier
):
return None
# Ignore own messages
if data.get("sender_id", None) is not None and data.get("sender_id", None) == self.__identifier:
return None

return data
return data

except json.JSONDecodeError as ex:
self.__logger.exception(ex)
except json.JSONDecodeError as ex:
self.__logger.exception(ex)

return None

Expand Down
33 changes: 14 additions & 19 deletions redisdb_exchange_plugin/exchange.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,19 @@
Redis DB exchange plugin exchange service
"""

# Library dependencies
# Python base dependencies
import json
import logging
import time
from typing import Dict, Optional
from threading import Thread
from kink import inject
from typing import Dict, Optional

# Library dependencies
import modules_metadata.exceptions as metadata_exceptions
from exchange_plugin.consumer import IConsumer
from exchange_plugin.dispatcher import EventDispatcher
from exchange_plugin.events.messages import MessageReceivedEvent
import modules_metadata.exceptions as metadata_exceptions
from kink import inject
from modules_metadata.loader import load_schema
from modules_metadata.routing import RoutingKey
from modules_metadata.types import ModuleOrigin
Expand All @@ -50,6 +52,7 @@ class RedisExchange(Thread):
@author Adam Kadlec <adam.kadlec@fastybird.com>
"""

__redis_client: RedisClient

__event_dispatcher: EventDispatcher
Expand Down Expand Up @@ -144,10 +147,10 @@ def __receive(self, data: Dict) -> None:
)

if (
routing_key is not None
and origin is not None
and data.get("data", None) is not None
and isinstance(data.get("data", None), dict) is True
routing_key is not None
and origin is not None
and data.get("data", None) is not None
and isinstance(data.get("data", None), dict) is True
):
data = self.__validate_data(
origin=origin,
Expand All @@ -168,7 +171,7 @@ def __receive(self, data: Dict) -> None:
origin=origin,
routing_key=routing_key,
data=data,
)
),
)

else:
Expand All @@ -181,11 +184,7 @@ def __receive(self, data: Dict) -> None:

@staticmethod
def __validate_origin(origin: Optional[str]) -> Optional[ModuleOrigin]:
if (
origin is not None
and isinstance(origin, str) is True
and ModuleOrigin.has_value(origin)
):
if origin is not None and isinstance(origin, str) is True and ModuleOrigin.has_value(origin):
return ModuleOrigin(origin)

return None
Expand All @@ -194,11 +193,7 @@ def __validate_origin(origin: Optional[str]) -> Optional[ModuleOrigin]:

@staticmethod
def __validate_routing_key(routing_key: Optional[str]) -> Optional[RoutingKey]:
if (
routing_key is not None
and isinstance(routing_key, str) is True
and RoutingKey.has_value(routing_key)
):
if routing_key is not None and isinstance(routing_key, str) is True and RoutingKey.has_value(routing_key):
return RoutingKey(routing_key)

return None
Expand Down
15 changes: 9 additions & 6 deletions redisdb_exchange_plugin/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
Redis DB exchange plugin logger
"""

# App dependencies
# Python base dependencies
import logging

# Library dependencies
from kink import inject


Expand All @@ -31,6 +33,7 @@ class Logger:
@author Adam Kadlec <adam.kadlec@fastybird.com>
"""

__logger: logging.Logger

# -----------------------------------------------------------------------------
Expand All @@ -46,30 +49,30 @@ def set_logger(self, logger: logging.Logger) -> None:

# -----------------------------------------------------------------------------

def debug(self, msg: str, *args, **kwargs) -> None:
def debug(self, msg: str, *args, **kwargs) -> None: # type: ignore[no-untyped-def]
"""Log debugging message"""
self.__logger.debug(msg, *args, **kwargs)

# -----------------------------------------------------------------------------

def info(self, msg: str, *args, **kwargs) -> None:
def info(self, msg: str, *args, **kwargs) -> None: # type: ignore[no-untyped-def]
"""Log information message"""
self.__logger.info(msg, *args, **kwargs)

# -----------------------------------------------------------------------------

def warning(self, msg: str, *args, **kwargs) -> None:
def warning(self, msg: str, *args, **kwargs) -> None: # type: ignore[no-untyped-def]
"""Log warning message"""
self.__logger.warning(msg, *args, **kwargs)

# -----------------------------------------------------------------------------

def error(self, msg: str, *args, **kwargs) -> None:
def error(self, msg: str, *args, **kwargs) -> None: # type: ignore[no-untyped-def]
"""Log error message"""
self.__logger.error(msg, *args, **kwargs)

# -----------------------------------------------------------------------------

def exception(self, msg: Exception, *args, exc_info: bool = True, **kwargs) -> None:
def exception(self, msg: Exception, *args, exc_info: bool = True, **kwargs) -> None: # type: ignore[no-untyped-def]
"""Log thrown exception"""
self.__logger.exception(msg, *args, exc_info, **kwargs)
5 changes: 4 additions & 1 deletion redisdb_exchange_plugin/publisher.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
Redis DB exchange plugin publisher
"""

# Library dependencies
# Python base dependencies
from typing import Dict, Optional

# Library dependencies
from exchange_plugin.publisher import IPublisher
from kink import inject
from modules_metadata.routing import RoutingKey
Expand All @@ -39,6 +41,7 @@ class Publisher(IPublisher): # pylint: disable=too-few-public-methods
@author Adam Kadlec <adam.kadlec@fastybird.com>
"""

__redis_client: RedisClient

# -----------------------------------------------------------------------------
Expand Down
Empty file.
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def find_version(*file_paths):
long_description_content_type="text/markdown",
python_requires=">=3.7",
packages=find_packages(),
package_data={"redisdb_exchange_plugin": ["py.typed"]},
install_requires=[
"fastybird-exchange-plugin",
"fastybird-modules-metadata",
Expand Down
Empty file added tests/stubs/__init__.pyi
Empty file.
13 changes: 13 additions & 0 deletions tests/stubs/redis/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from typing import Any, Optional

from redis.client import PubSub


class Redis(object):
def __init__(self, host: str = "localhost", port: int = 6379, username: Optional[str] = None, password: Optional[str] = None) -> None: ...

def close(self) -> None: ...

def publish(self, channel: str, message: str) -> int: ...

def pubsub(self, **kwargs: Any) -> PubSub: ...
11 changes: 11 additions & 0 deletions tests/stubs/redis/client.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from typing import Dict, Union


class PubSub:
def subscribe(self, *args: str, **kwargs: str) -> int: ...

def unsubscribe(self, *args: str) -> int: ...

def close(self) -> None: ...

def get_message(self, ignore_subscribe_messages: bool = False, timeout: int = 0) -> Dict[str, Union[bytes, str, int, None]]: ...

0 comments on commit 83be412

Please sign in to comment.