mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-11-23 11:34:18 +00:00
💥 Tested filters!
This commit is contained in:
parent
b44290bd98
commit
9b4b382145
6 changed files with 119 additions and 16 deletions
|
@ -3,7 +3,7 @@
|
||||||
<module name="royalnet-6" />
|
<module name="royalnet-6" />
|
||||||
<option name="INTERPRETER_OPTIONS" value="" />
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
<option name="PARENT_ENVS" value="true" />
|
<option name="PARENT_ENVS" value="true" />
|
||||||
<option name="SDK_HOME" value="" />
|
<option name="SDK_HOME" value="$USER_HOME$/.cache/pypoetry/virtualenvs/royalnet-1-y9ycdx-py3.9/bin/python" />
|
||||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
<option name="IS_MODULE_SDK" value="true" />
|
<option name="IS_MODULE_SDK" value="true" />
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
|
|
14
poetry.lock
generated
14
poetry.lock
generated
|
@ -6,6 +6,14 @@ category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-timeout"
|
||||||
|
version = "3.0.1"
|
||||||
|
description = "Timeout context manager for asyncio programs"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5.3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atomicwrites"
|
name = "atomicwrites"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -409,13 +417,17 @@ socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.0"
|
lock-version = "1.0"
|
||||||
python-versions = "^3.8"
|
python-versions = "^3.8"
|
||||||
content-hash = "4363aefc0ea9322445ee375edce430712159829b5ca40561eea7cd74bbf0a7bd"
|
content-hash = "e53fe1488633a7fa98cd473258ed6501d33201c07c0169b0a13a5f8f38149ac4"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
alabaster = [
|
alabaster = [
|
||||||
{file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"},
|
{file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"},
|
||||||
{file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"},
|
{file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"},
|
||||||
]
|
]
|
||||||
|
async-timeout = [
|
||||||
|
{file = "async-timeout-3.0.1.tar.gz", hash = "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f"},
|
||||||
|
{file = "async_timeout-3.0.1-py3-none-any.whl", hash = "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"},
|
||||||
|
]
|
||||||
atomicwrites = [
|
atomicwrites = [
|
||||||
{file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
|
{file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
|
||||||
{file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
|
{file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
|
||||||
|
|
|
@ -16,6 +16,7 @@ pytest = "^6.1.1"
|
||||||
pytest-asyncio = "^0.14.0"
|
pytest-asyncio = "^0.14.0"
|
||||||
sphinx = "^3.3.1"
|
sphinx = "^3.3.1"
|
||||||
sphinx_rtd_theme = "^0.5.0"
|
sphinx_rtd_theme = "^0.5.0"
|
||||||
|
async-timeout = "^3.0.1"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry>=0.12"]
|
requires = ["poetry>=0.12"]
|
||||||
|
|
|
@ -25,17 +25,30 @@ class Filter:
|
||||||
"""
|
"""
|
||||||
Wait until an :class:`object` leaves the queue and passes through the filter, then return it.
|
Wait until an :class:`object` leaves the queue and passes through the filter, then return it.
|
||||||
|
|
||||||
:return: The :class:`object` which entered the queue.
|
:return: The :class:`object` which left the queue.
|
||||||
"""
|
"""
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
result = await self.func(None)
|
return await self.get_single()
|
||||||
except exc.Discard as e:
|
except exc.Discard:
|
||||||
log.debug(str(e))
|
|
||||||
continue
|
continue
|
||||||
else:
|
|
||||||
log.debug(f"Dequeued {result}")
|
async def get_single(self) -> Any:
|
||||||
return result
|
"""
|
||||||
|
Let one :class:`object` pass through the filter, then either return it or raise an error if the object should be
|
||||||
|
discarded.
|
||||||
|
|
||||||
|
:return: The :class:`object` which left the queue.
|
||||||
|
:raises exc.Discard: If the object was filtered.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
result = await self.func(None)
|
||||||
|
except exc.Discard as e:
|
||||||
|
log.debug(str(e))
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
log.debug(f"Dequeued {result}")
|
||||||
|
return result
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _deco_filter(c: Callable[[Any], bool], *, error: str):
|
def _deco_filter(c: Callable[[Any], bool], *, error: str):
|
||||||
|
@ -221,7 +234,7 @@ class Filter:
|
||||||
:param choices: The pattern that should be matched by the text.
|
:param choices: The pattern that should be matched by the text.
|
||||||
:return: A new :class:`Filter` with the new requirements.
|
:return: A new :class:`Filter` with the new requirements.
|
||||||
"""
|
"""
|
||||||
return self.__class__(self._deco_check(lambda o: o in choices, error="Not a valid choice")(self.func))
|
return self.filter(lambda o: o in choices, error="Not a valid choice")
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
|
|
|
@ -18,18 +18,23 @@ class Sentry:
|
||||||
The size of the object :attr:`.queue`.
|
The size of the object :attr:`.queue`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, filter_type: Type[Filter] = Filter):
|
||||||
self.queue: asyncio.Queue = asyncio.Queue(maxsize=12)
|
self.queue: asyncio.Queue = asyncio.Queue(maxsize=self.QUEUE_SIZE)
|
||||||
"""
|
"""
|
||||||
An object queue where incoming :class:`object` are stored.
|
An object queue where incoming :class:`object` are stored, with a size limit of :attr:`.QUEUE_SIZE`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.filter_type: Type[Filter] = filter_type
|
||||||
|
"""
|
||||||
|
The filter to be used in :meth:`.f` calls, by default :class:`.filters.Filter`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<Sentry>"
|
return f"<Sentry>"
|
||||||
|
|
||||||
async def f(self):
|
def f(self):
|
||||||
"""
|
"""
|
||||||
Create a :class:`.filters.Filter` object, which can be configured through its fluent interface.
|
Create a :attr:`.filter_type` object, which can be configured through its fluent interface.
|
||||||
|
|
||||||
Remember to call ``.get()`` on the end of the chain to finally get the object.
|
Remember to call ``.get()`` on the end of the chain to finally get the object.
|
||||||
|
|
||||||
|
@ -43,7 +48,9 @@ class Sentry:
|
||||||
|
|
||||||
:return: The created :class:`.filters.Filter`.
|
:return: The created :class:`.filters.Filter`.
|
||||||
"""
|
"""
|
||||||
return Filter(self.queue.get)
|
async def func(_):
|
||||||
|
return await self.queue.get()
|
||||||
|
return self.filter_type(func)
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
|
|
70
royalnet/engineer/tests/test_sentry.py
Normal file
70
royalnet/engineer/tests/test_sentry.py
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import pytest
|
||||||
|
import asyncio
|
||||||
|
import async_timeout
|
||||||
|
from .. import sentry, exc
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def s() -> sentry.Sentry:
|
||||||
|
return sentry.Sentry()
|
||||||
|
|
||||||
|
|
||||||
|
class TestSentry:
|
||||||
|
def test_creation(self, s: sentry.Sentry):
|
||||||
|
assert s
|
||||||
|
assert isinstance(s, sentry.Sentry)
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_put(self, s: sentry.Sentry):
|
||||||
|
await s.queue.put(None)
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get(self, s: sentry.Sentry):
|
||||||
|
await s.queue.put(None)
|
||||||
|
assert await s.queue.get() is None
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_f(self, s: sentry.Sentry):
|
||||||
|
await s.queue.put(None)
|
||||||
|
f = s.f()
|
||||||
|
assert f
|
||||||
|
assert isinstance(f, sentry.Filter)
|
||||||
|
assert hasattr(f, "get")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def discarding_filter() -> sentry.Filter:
|
||||||
|
async def discard(_):
|
||||||
|
raise exc.Discard(None, "This filter discards everything!")
|
||||||
|
|
||||||
|
return sentry.Filter(discard)
|
||||||
|
|
||||||
|
|
||||||
|
class TestFilter:
|
||||||
|
def test_creation(self):
|
||||||
|
f = sentry.Filter(lambda _: _)
|
||||||
|
assert f
|
||||||
|
assert isinstance(f, sentry.Filter)
|
||||||
|
|
||||||
|
class TestGetSingle:
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_success(self, s: sentry.Sentry):
|
||||||
|
await s.queue.put(None)
|
||||||
|
assert await s.f().get_single() is None
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_failure(self, discarding_filter: sentry.Filter):
|
||||||
|
with pytest.raises(exc.Discard):
|
||||||
|
await discarding_filter.get_single()
|
||||||
|
|
||||||
|
class TestGet:
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_success(self, s: sentry.Sentry):
|
||||||
|
await s.queue.put(None)
|
||||||
|
assert await s.f().get() is None
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_timeout(self, s: sentry.Sentry):
|
||||||
|
with pytest.raises(asyncio.TimeoutError):
|
||||||
|
async with async_timeout.timeout(0.05):
|
||||||
|
await s.f().get()
|
Loading…
Reference in a new issue