]> git.scottworley.com Git - paperdoorknob/commitdiff
Cleaner Fetcher interface
authorScott Worley <scottworley@scottworley.com>
Tue, 19 Dec 2023 09:16:03 +0000 (01:16 -0800)
committerScott Worley <scottworley@scottworley.com>
Wed, 20 Dec 2023 04:09:42 +0000 (20:09 -0800)
fetch.py [new file with mode: 0644]
fetch_test.py [new file with mode: 0644]
setup.py

diff --git a/fetch.py b/fetch.py
new file mode 100644 (file)
index 0000000..3c0c6a3
--- /dev/null
+++ b/fetch.py
@@ -0,0 +1,43 @@
+# paperdoorknob: Print glowfic
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, version 3.
+
+
+from abc import ABC, abstractmethod
+from contextlib import contextmanager
+from typing import Iterator
+
+import requests
+import requests_cache
+
+
+class Fetcher(ABC):
+    @abstractmethod
+    def fetch(self, url: str) -> bytes:
+        raise NotImplementedError()
+
+
+class _SessionFetcher(Fetcher):
+
+    def __init__(self, session: requests.Session, timeout: int) -> None:
+        self._session = session
+        self._timeout = timeout
+
+    def fetch(self, url: str) -> bytes:
+        with self._session.get(url, timeout=self._timeout) as r:
+            r.raise_for_status()
+            return r.content
+
+
+@contextmanager
+def DirectFetcher(timeout: int) -> Iterator[_SessionFetcher]:
+    with requests.session() as session:
+        yield _SessionFetcher(session, timeout)
+
+
+@contextmanager
+def CachingFetcher(cache_path: str, timeout: int) -> Iterator[_SessionFetcher]:
+    with requests_cache.CachedSession(cache_path, cache_control=True) as session:
+        yield _SessionFetcher(session, timeout)
diff --git a/fetch_test.py b/fetch_test.py
new file mode 100644 (file)
index 0000000..6bdf69e
--- /dev/null
@@ -0,0 +1,57 @@
+# paperdoorknob: Print glowfic
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, version 3.
+
+
+import unittest
+from requests import HTTPError
+from testing.fakeserver import FakeGlowficServer
+from fetch import CachingFetcher, DirectFetcher
+
+TIMEOUT = 8
+
+
+class TestFetch(unittest.TestCase):
+    def setUp(self) -> None:
+        self._server = self.enterContext(FakeGlowficServer())
+        self._port = self._server.port()
+
+    def testDirectFetch(self) -> None:
+        with DirectFetcher(TIMEOUT) as f:
+            f.fetch(f"http://localhost:{self._port}")
+            self.assertEqual(self._server.request_count(), 1)
+            f.fetch(f"http://localhost:{self._port}")
+            self.assertEqual(self._server.request_count(), 2)
+
+    def testFetchCaching(self) -> None:
+        with CachingFetcher("testcache", TIMEOUT) as f:
+            f.fetch(f"http://localhost:{self._port}")
+            self.assertEqual(self._server.request_count(), 1)
+            f.fetch(f"http://localhost:{self._port}")
+            self.assertEqual(self._server.request_count(), 1)
+
+    def testFetchPersistentCaching(self) -> None:
+        with CachingFetcher("testpersistentcache", TIMEOUT) as f:
+            f.fetch(f"http://localhost:{self._port}")
+            self.assertEqual(self._server.request_count(), 1)
+        with CachingFetcher("testpersistentcache", TIMEOUT) as f:
+            f.fetch(f"http://localhost:{self._port}")
+            self.assertEqual(self._server.request_count(), 1)
+
+    def testFetchErrors(self) -> None:
+        with DirectFetcher(TIMEOUT) as f:
+            with self.assertRaises(HTTPError):
+                f.fetch(f"http://localhost:{self._port}/not_found")
+            with self.assertRaises(HTTPError):
+                f.fetch(f"http://localhost:{self._port}/server_error")
+        with CachingFetcher("testerrorscache", TIMEOUT) as f:
+            with self.assertRaises(HTTPError):
+                f.fetch(f"http://localhost:{self._port}/not_found")
+            with self.assertRaises(HTTPError):
+                f.fetch(f"http://localhost:{self._port}/server_error")
+
+
+if __name__ == '__main__':
+    unittest.main()
index bd23bdde09d1d10722c8605a2d8fe24b4048a8ae..27980a1131a6dc2b619b4a509589ef4987ba0981 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -7,7 +7,10 @@ setup(
     author="Scott Worley",
     author_email="scottworley@scottworley.com",
     url="https://git.scottworley.com/paperdoorknob",
     author="Scott Worley",
     author_email="scottworley@scottworley.com",
     url="https://git.scottworley.com/paperdoorknob",
-    py_modules=['paperdoorknob'],
+    py_modules=[
+        'fetch',
+        'paperdoorknob',
+    ],
     license="GPL-3.0",
     entry_points={'console_scripts': ['paperdoorknob = paperdoorknob:main']},
 )
     license="GPL-3.0",
     entry_points={'console_scripts': ['paperdoorknob = paperdoorknob:main']},
 )