8000 Add Interrogate to CI pipeline by mjcaley · Pull Request #296 · mjcaley/aiospamc · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add Interrogate to CI pipeline #296

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .azure-pipelines/templates/ci_steps.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ steps:
versionSpec: ${{ parameters.PythonVersion }}
displayName: 'Use Python ${{ parameters.PythonVersion }}'

- script: python -m pip install --upgrade pip
displayName: 'Upgrade Pip'

- script: |
curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python
displayName: 'Installing Poetry'
Expand Down Expand Up @@ -40,6 +43,10 @@ steps:
black --check "$BUILD_SOURCESDIRECTORY"
displayName: 'Run black'

- script: |
interrogate
displayName: 'Run interrogate for docstring coverage'

- script: |
sudo apt-get -y install spamassassin
displayName: 'Install SpamAssassin'
Expand Down
39 changes: 39 additions & 0 deletions aiospamc/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ class ConnectionManager:
"""Stores connection parameters and creates connections."""

def __init__(self, timeout: Timeout = None) -> None:
"""ConnectionManager constructor.

:param timeout: Timeout configuration
"""

self.timeout = timeout or Timeout()
self._logger = logging.getLogger("aiospamc.connections")

Expand Down Expand Up @@ -88,6 +93,13 @@ async def request(self, data: bytes) -> bytes:
return response

async def _send(self, data: bytes) -> bytes:
"""Opens a connection, sends data to the writer, waits for the reader, then returns the response.

:param data: Data to send.

:return: Byte data from the response.
"""

reader, writer = await self._connect()

writer.write(data)
Expand All @@ -102,6 +114,13 @@ async def _send(self, data: bytes) -> bytes:
return response

async def _receive(self, reader: asyncio.StreamReader) -> bytes:
"""Takes a reader and returns the response.

:param reader: asyncio reader.

:return: Byte data from the response.
"""

start = monotonic()
try:
response = await asyncio.wait_for(reader.read(), self.timeout.response)
Expand All @@ -127,6 +146,11 @@ async def _receive(self, reader: asyncio.StreamReader) -> bytes:
return response

async def _connect(self) -> Tuple[asyncio.StreamReader, asyncio.StreamWriter]:
"""Opens a connection from the connection manager.

:return: Tuple or asyncio reader and writer.
"""

start = monotonic()
try:
reader, writer = await asyncio.wait_for(
Expand Down Expand Up @@ -165,6 +189,8 @@ def connection_string(self) -> str:


class TcpConnectionManager(ConnectionManager):
"""Connection manager for TCP connections."""

def __init__(
self,
host: str,
Expand All @@ -177,6 +203,7 @@ def __init__(
:param host: Hostname or IP address.
:param port: TCP port.
:param ssl_context: SSL context.
:param timeout: Timeout configuration.
"""

super().__init__(timeout)
Expand Down Expand Up @@ -216,10 +243,13 @@ def connection_string(self) -> str:


class UnixConnectionManager(ConnectionManager):
"""Connection manager for Unix pipes."""

def __init__(self, path: str, timeout: Timeout = None):
"""UnixConnectionManager constructor.

:param path: Unix socket path.
:param timeout: Timeout configuration
"""

super().__init__(timeout)
Expand Down Expand Up @@ -288,6 +318,15 @@ def new_connection(
timeout: Optional[Timeout] = None,
context: Optional[ssl.SSLContext] = None,
) -> ConnectionManager:
"""Create a new connection manager.

:param host: TCP hostname.
:param port: TCP port number.
:param socket_path: Unix socket path.
:param timeout: Timeout configuration.
:param context: SSL context configuration.
"""

if socket_path:
return UnixConnectionManager(socket_path, timeout=timeout)
elif host and port:
Expand Down
86 changes: 86 additions & 0 deletions aiospamc/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ class ResponseException(Exception):
"""Base class for exceptions raised from a response."""

def __init__(self, code: int, message: str) -> None:
"""ResponseException constructor.

:param code: Response code number.
:param message: Message response.
"""

self.code = code
super().__init__(message)

Expand All @@ -39,104 +45,179 @@ class UsageException(ResponseException):
"""Command line usage error."""

def __init__(self, message: str) -> None:
"""UsageException constructor.

:param message: Message response.
"""

super().__init__(64, message)


class DataErrorException(ResponseException):
"""Data format error."""

def __init__(self, message: str) -> None:
"""DataErrorException constructor.

:param message: Message response.
"""

super().__init__(65, message)


class NoInputException(ResponseException):
"""Cannot open input."""

def __init__(self, message: str) -> None:
"""NoInputException constructor.

:param message: Message response.
"""

super().__init__(66, message)


class NoUserException(ResponseException):
"""Addressee unknown."""

def __init__(self, message: str) -> None:
"""NoUserException constructor.

:param message: Message response.
"""

super().__init__(67, message)


class NoHostException(ResponseException):
"""Hostname unknown."""

def __init__(self, message: str) -> None:
"""NoHostException constructor.

:param message: Message response.
"""

super().__init__(68, message)


class UnavailableException(ResponseException):
"""Service unavailable."""

def __init__(self, message: str) -> None:
"""UnavailableException constructor.

:param message: Message response.
"""

super().__init__(69, message)


class InternalSoftwareException(ResponseException):
"""Internal software error."""

def __init__(self, message: str) -> None:
"""InternalSoftwareException constructor.

:param message: Message response.
"""

super().__init__(70, message)


class OSErrorException(ResponseException):
"""System error (e.g. can't fork the process)."""

def __init__(self, message: str) -> None:
"""OSErrorException constructor.

:param message: Message response.
"""

super().__init__(71, message)


class OSFileException(ResponseException):
"""Critical operating system file missing."""

def __init__(self, message: str) -> None:
"""OSFileException constructor.

:param message: Message response.
"""

super().__init__(72, message)


class CantCreateException(ResponseException):
"""Can't create (user) output file."""

def __init__(self, message: str) -> None:
"""CantCreateException constructor.

:param message: Message response.
"""

super().__init__(73, message)


class IOErrorException(ResponseException):
"""Input/output error."""

def __init__(self, message: str) -> None:
"""IOErrorException constructor.

:param message: Message response.
"""

super().__init__(74, message)


class TemporaryFailureException(ResponseException):
"""Temporary failure, user is invited to try again."""

def __init__(self, message: str) -> None:
"""TemporaryFailureException constructor.

:param message: Message response.
"""

super().__init__(75, message)


class ProtocolException(ResponseException):
"""Remote error in protocol."""

def __init__(self, message: str) -> None:
"""ProtocolException constructor.

:param message: Message response.
"""

super().__init__(76, message)


class NoPermissionException(ResponseException):
"""Permission denied."""

def __init__(self, message: str) -> None:
"""NoPermissionException constructor.

:param message: Message response.
"""

super().__init__(77, message)


class ConfigException(ResponseException):
"""Configuration error."""

def __init__(self, message: str) -> None:
"""ConfigException constructor.

:param message: Message response.
"""

super().__init__(78, message)


Expand All @@ -150,6 +231,11 @@ class ServerTimeoutException(ResponseException, TimeoutException):
"""Timeout exception from the server."""

def __init__(self, message: str) -> None:
"""ServerTimeoutException constructor.

:param message: Message response.
"""

super().__init__(79, message)


Expand Down
21 changes: 21 additions & 0 deletions aiospamc/frontend.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@


class Client(NamedTuple):
"""Client tuple containing factories."""

ssl_context_factory: SSLFactory
connection_factory: ConnectionFactory
parser_factory: Type[ResponseParser]
Expand Down Expand Up @@ -104,13 +106,32 @@ def _new_connection(
timeout: Timeout = None,
verify: Any = None,
) -> ConnectionManager:
"""Helper function to create a new connection manager object depending on inputs.

:param connection_factory: Factory function for connection manager.
:param ssl_context_factory: Factory function for SSL context.
:param host: SPAMD TCP hostname.
:param port: SPAMD TCP port number.
:param socket_path: Unix socket path.
:param timeout: Timeout configuration.
:param verify: SSL context configuration.

:return: Instance of the `ConnectionManager` based on inputs.
"""

ssl_context = ssl_context_factory(verify)
connection = connection_factory(host, port, socket_path, timeout, ssl_context)

return connection


def _add_headers(req: Request, user: Optional[str], compress: Optional[bool]) -> None:
"""Helper function for adding user or compress headers to a request.

:param req: Request to modify.
:param user: Username to add to the user header.
:param compress: Boolean for whether to add the compress header.
"""
if user:
req.headers["User"] = UserValue(user)
if compress:
Expand Down
7 changes: 7 additions & 0 deletions aiospamc/header_values.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@


class HeaderValue:
"""Base class for header values."""

def __bytes__(self):
raise NotImplementedError

Expand All @@ -19,6 +21,11 @@ class BytesHeaderValue(HeaderValue):
"""

def __init__(self, value: bytes) -> None:
"""BytesHeaderValue constructor.

:param value: Value of byte data.
"""

self.value = value

def __str__(self) -> str:
Expand Down
Loading
0