Refactor WrapperHandler
- validation checks for initialization logic - fix SocialAPIsTool - fix RedditWrapper
This commit is contained in:
@@ -26,7 +26,7 @@ class SocialAPIsTool(SocialWrapper, Toolkit):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
wrappers = [RedditWrapper]
|
wrappers = [RedditWrapper]
|
||||||
self.wrapper_handler: WrapperHandler[SocialWrapper] = WrapperHandler(wrappers)
|
self.wrapper_handler: WrapperHandler[SocialWrapper] = WrapperHandler.build_wrappers(wrappers)
|
||||||
|
|
||||||
Toolkit.__init__(
|
Toolkit.__init__(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class SocialWrapper:
|
|||||||
Base class for social media API wrappers.
|
Base class for social media API wrappers.
|
||||||
All social media API wrappers should inherit from this class and implement the methods.
|
All social media API wrappers should inherit from this class and implement the methods.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_top_crypto_posts(self, limit: int = 5) -> list[SocialPost]:
|
def get_top_crypto_posts(self, limit: int = 5) -> list[SocialPost]:
|
||||||
"""
|
"""
|
||||||
Get top cryptocurrency-related posts, optionally limited by total.
|
Get top cryptocurrency-related posts, optionally limited by total.
|
||||||
|
|||||||
@@ -35,15 +35,15 @@ class RedditWrapper(SocialWrapper):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.client_id = os.getenv("REDDIT_API_CLIENT_ID")
|
client_id = os.getenv("REDDIT_API_CLIENT_ID")
|
||||||
assert self.client_id is not None, "REDDIT_API_CLIENT_ID environment variable is not set"
|
assert client_id is not None, "REDDIT_API_CLIENT_ID environment variable is not set"
|
||||||
|
|
||||||
self.client_secret = os.getenv("REDDIT_API_CLIENT_SECRET")
|
client_secret = os.getenv("REDDIT_API_CLIENT_SECRET")
|
||||||
assert self.client_secret is not None, "REDDIT_API_CLIENT_SECRET environment variable is not set"
|
assert client_secret is not None, "REDDIT_API_CLIENT_SECRET environment variable is not set"
|
||||||
|
|
||||||
self.tool = Reddit(
|
self.tool = Reddit(
|
||||||
client_id=self.client_id,
|
client_id=client_id,
|
||||||
client_secret=self.client_secret,
|
client_secret=client_secret,
|
||||||
user_agent="upo-appAI",
|
user_agent="upo-appAI",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ class WrapperHandler(Generic[W]):
|
|||||||
try_per_wrapper (int): Number of retries per wrapper before switching to the next.
|
try_per_wrapper (int): Number of retries per wrapper before switching to the next.
|
||||||
retry_delay (int): Delay in seconds between retries.
|
retry_delay (int): Delay in seconds between retries.
|
||||||
"""
|
"""
|
||||||
|
assert not WrapperHandler.__check(wrappers), "All wrappers must be instances of their respective classes. Use `build_wrappers` to create the WrapperHandler."
|
||||||
|
|
||||||
self.wrappers = wrappers
|
self.wrappers = wrappers
|
||||||
self.retry_per_wrapper = try_per_wrapper
|
self.retry_per_wrapper = try_per_wrapper
|
||||||
self.retry_delay = retry_delay
|
self.retry_delay = retry_delay
|
||||||
@@ -87,6 +89,10 @@ class WrapperHandler(Generic[W]):
|
|||||||
raise Exception("All wrappers failed")
|
raise Exception("All wrappers failed")
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __check(wrappers: list[W]) -> bool:
|
||||||
|
return all(w.__class__ is type for w in wrappers)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def build_wrappers(constructors: Iterable[Type[W]], try_per_wrapper: int = 3, retry_delay: int = 2) -> 'WrapperHandler[W]':
|
def build_wrappers(constructors: Iterable[Type[W]], try_per_wrapper: int = 3, retry_delay: int = 2) -> 'WrapperHandler[W]':
|
||||||
"""
|
"""
|
||||||
@@ -102,6 +108,8 @@ class WrapperHandler(Generic[W]):
|
|||||||
Raises:
|
Raises:
|
||||||
Exception: If no wrappers could be initialized.
|
Exception: If no wrappers could be initialized.
|
||||||
"""
|
"""
|
||||||
|
assert WrapperHandler.__check(constructors), f"All constructors must be classes. Received: {constructors}"
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
for wrapper_class in constructors:
|
for wrapper_class in constructors:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -25,6 +25,29 @@ class FailingWrapperWithParameters(MockWrapperWithParameters):
|
|||||||
|
|
||||||
@pytest.mark.wrapper
|
@pytest.mark.wrapper
|
||||||
class TestWrapperHandler:
|
class TestWrapperHandler:
|
||||||
|
def test_init_failing(self):
|
||||||
|
with pytest.raises(AssertionError) as exc_info:
|
||||||
|
WrapperHandler([MockWrapper, MockWrapper2])
|
||||||
|
assert exc_info.type == AssertionError
|
||||||
|
|
||||||
|
def test_init_failing_empty(self):
|
||||||
|
with pytest.raises(AssertionError) as exc_info:
|
||||||
|
WrapperHandler.build_wrappers([])
|
||||||
|
assert exc_info.type == AssertionError
|
||||||
|
|
||||||
|
def test_init_failing_with_instances(self):
|
||||||
|
with pytest.raises(AssertionError) as exc_info:
|
||||||
|
WrapperHandler.build_wrappers([MockWrapper(), MockWrapper2()])
|
||||||
|
assert exc_info.type == AssertionError
|
||||||
|
|
||||||
|
def test_init_not_failing(self):
|
||||||
|
handler = WrapperHandler.build_wrappers([MockWrapper, MockWrapper2])
|
||||||
|
assert handler is not None
|
||||||
|
assert len(handler.wrappers) == 2
|
||||||
|
handler = WrapperHandler([MockWrapper(), MockWrapper2()])
|
||||||
|
assert handler is not None
|
||||||
|
assert len(handler.wrappers) == 2
|
||||||
|
|
||||||
def test_all_wrappers_fail(self):
|
def test_all_wrappers_fail(self):
|
||||||
wrappers = [FailingWrapper, FailingWrapper]
|
wrappers = [FailingWrapper, FailingWrapper]
|
||||||
handler: WrapperHandler[MockWrapper] = WrapperHandler.build_wrappers(wrappers, try_per_wrapper=2, retry_delay=0)
|
handler: WrapperHandler[MockWrapper] = WrapperHandler.build_wrappers(wrappers, try_per_wrapper=2, retry_delay=0)
|
||||||
|
|||||||
Reference in New Issue
Block a user