Skip to content

Commit

Permalink
aio.web: Add app
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Northey <ryan@synca.io>
  • Loading branch information
phlax committed Sep 5, 2023
1 parent 8a8f4f6 commit 3a0017d
Show file tree
Hide file tree
Showing 18 changed files with 264 additions and 0 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,21 @@ pypi: https://pypi.org/project/aio.run.runner
---


#### [aio.web](aio.web)

version: 0.1.0.dev0

pypi: https://pypi.org/project/aio.web

##### requirements:

- [abstracts](https://pypi.org/project/abstracts) >=0.0.12
- [aiohttp](https://pypi.org/project/aiohttp)
- [pyyaml](https://pypi.org/project/pyyaml)

---


#### [dependatool](dependatool)

version: 0.2.3.dev0
Expand Down
2 changes: 2 additions & 0 deletions aio.web/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

toolshed_package("aio.web")
5 changes: 5 additions & 0 deletions aio.web/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

aio.web
=======

Web utils for asyncio.
1 change: 1 addition & 0 deletions aio.web/VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.1.0-dev
18 changes: 18 additions & 0 deletions aio.web/aio/web/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

toolshed_library(
"aio.web",
dependencies=[
"//deps:reqs#abstracts",
"//deps:reqs#aiohttp",
"//deps:reqs#pyyaml",
],
sources=[
"__init__.py",
"abstract/__init__.py",
"abstract/downloader.py",
"downloader.py",
"exceptions.py",
"interface.py",
"typing.py",
],
)
14 changes: 14 additions & 0 deletions aio.web/aio/web/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

from .abstract import (
ADownloader,
AChecksumDownloader)
from .interface import (
IDownloader,
IChecksumDownloader)


__all__ = (
"ADownloader",
"AChecksumDownloader",
"IDownloader",
"IChecksumDownloader")
7 changes: 7 additions & 0 deletions aio.web/aio/web/abstract/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from .downloader import ADownloader, AChecksumDownloader


__all__ = (
"ADownloader",
"AChecksumDownloader",
)
43 changes: 43 additions & 0 deletions aio.web/aio/web/abstract/downloader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

import hashlib

import aiohttp

import abstracts

from aio.web import exceptions, interface


@abstracts.implementer(interface.IDownloader)
class ADownloader(metaclass=abstracts.Abstraction):

def __init__(self, url: str) -> None:
self.url = url

async def download(self) -> bytes:
"""Download content from the interwebs."""
async with aiohttp.ClientSession() as session:
async with session.get(self.url) as resp:
return await resp.content.read()


@abstracts.implementer(interface.IChecksumDownloader)
class AChecksumDownloader(ADownloader, metaclass=abstracts.Abstraction):

def __init__(self, url: str, sha: str) -> None:
super().__init__(url)
self.sha = sha

async def checksum(self, content: bytes) -> None:
"""Download content from the interwebs."""
# do this in a thread
m = hashlib.sha256()
m.update(content)
if m.digest().hex() != self.sha:
raise ChecksumError(
f"Bad checksum, {m.digest().hex()}, expected {self.sha}")

async def download(self) -> bytes:
content = await super().download()
await self.checksum(content)
return content
14 changes: 14 additions & 0 deletions aio.web/aio/web/downloader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

import abstracts

from aio.web import abstract


@abstracts.implementer(abstract.ADownloader)
class Downloader:
pass


@abstracts.implementer(abstract.AChecksumDownloader)
class ChecksumDownloader:
pass
7 changes: 7 additions & 0 deletions aio.web/aio/web/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

class ChecksumError(Exception):
pass


class DownloadError(Exception):
pass
20 changes: 20 additions & 0 deletions aio.web/aio/web/interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

from aiohttp import web

import abstracts


class IDownloader(metaclass=abstracts.Interface):

@abstracts.interfacemethod
async def download(self) -> web.Response:
"""Download content from the interwebs."""
raise NotImplementedError


class IChecksumDownloader(IDownloader, metaclass=abstracts.Interface):

@abstracts.interfacemethod
async def checksum(self, content: bytes) -> bool:
"""Checksum some content."""
raise NotImplementedError
Empty file added aio.web/aio/web/py.typed
Empty file.
Empty file added aio.web/aio/web/typing.py
Empty file.
55 changes: 55 additions & 0 deletions aio.web/setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
[metadata]
name = aio.web
version = file: VERSION
author = Ryan Northey
author_email = ryan@synca.io
maintainer = Ryan Northey
maintainer_email = ryan@synca.io
license = Apache Software License 2.0
url = https://github.com/envoyproxy/toolshed/tree/main/aio.web
description = A collection of functional utils for asyncio
long_description = file: README.rst
classifiers =
Development Status :: 4 - Beta
Framework :: Pytest
Intended Audience :: Developers
Topic :: Software Development :: Testing
Programming Language :: Python
Programming Language :: Python :: 3
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: Implementation :: CPython
Operating System :: OS Independent
License :: OSI Approved :: Apache Software License

[options]
python_requires = >=3.8
py_modules = aio.web
packages = find_namespace:
install_requires =
abstracts>=0.0.12
aiohttp
pyyaml

[options.extras_require]
test =
pytest
pytest-asyncio
pytest-coverage
pytest-iters
pytest-patches
lint = flake8
types =
mypy
publish = wheel

[options.package_data]
* = py.typed

[options.packages.find]
include = aio.*
exclude =
build.*
tests.*
dist.*
5 changes: 5 additions & 0 deletions aio.web/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env python

from setuptools import setup # type:ignore

setup()
10 changes: 10 additions & 0 deletions aio.web/tests/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

toolshed_tests(
"aio.web",
dependencies=[
"//deps:reqs#abstracts",
"//deps:reqs#aiohttp",
"//deps:reqs#pyyaml",
"//deps:reqs#pytest-asyncio",
],
)
36 changes: 36 additions & 0 deletions aio.web/tests/test_downloader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

from aio.web import abstract, downloader


def test_downloader_constructor(patches):
args = tuple(f"ARG{i}" for i in range(0, 3))
kwargs = {f"K{i}": f"V{i}" for i in range(0, 3)}
patched = patches(
"abstract.ADownloader.__init__",
prefix="aio.web.downloader")

with patched as (m_super, ):
m_super.return_value = None
dl = downloader.Downloader(*args, **kwargs)

assert isinstance(dl, abstract.ADownloader)
assert (
m_super.call_args
== [args, kwargs])


def test_checksum_downloader_constructor(patches):
args = tuple(f"ARG{i}" for i in range(0, 3))
kwargs = {f"K{i}": f"V{i}" for i in range(0, 3)}
patched = patches(
"abstract.AChecksumDownloader.__init__",
prefix="aio.web.downloader")

with patched as (m_super, ):
m_super.return_value = None
dl = downloader.ChecksumDownloader(*args, **kwargs)

assert isinstance(dl, abstract.AChecksumDownloader)
assert (
m_super.call_args
== [args, kwargs])
12 changes: 12 additions & 0 deletions aio.web/tests/test_interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

import pytest

from aio import web


@pytest.mark.parametrize(
"interface",
[web.IDownloader,
web.IChecksumDownloader])
async def test_interfaces(iface, interface):
await iface(interface).check()

0 comments on commit 3a0017d

Please sign in to comment.