Skip to content

Commit

Permalink
docs: add more docstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
alexsavio committed Jul 15, 2019
1 parent a8e2e40 commit 79b5d5a
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 9 deletions.
2 changes: 2 additions & 0 deletions lambda_handlers/formatters/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
"""Input/Output formatter classes."""

from .format import Format # noqa
1 change: 1 addition & 0 deletions lambda_handlers/formatters/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def __init__(self, content_type: str):
self.content_type = content_type

def __call__(self, fn):
"""Decorate functions."""
return Format(
content_type=self.content_type,
format=fn,
Expand Down
4 changes: 2 additions & 2 deletions lambda_handlers/handlers/lambda_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ class LambdaHandler(ABC):
Contain hooks to be called before, after, and when an exception is raised.
"""

def __init__(self, handler: Optional[Callable] = None):
"""Constructor in case the handler is called directly without parenthesis."""
self._handler = handler

def __call__(self, handler: Callable):
"""The decorator function."""
"""Decorate `handler`."""
@wraps(handler)
def wrapper(event, context):
return self._call_handler(handler, event, context)
Expand Down
7 changes: 6 additions & 1 deletion lambda_handlers/handlers/mixins/formatting_mixin.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
"""Formatting mixin."""


class FormattingMixin:
"""A mixin for formatting."""
"""A mixin to user Formatters."""

def format_input(self, event):
"""Parse `event` and return the result."""
return self._input_format.format(event)

def format_output(self, result):
"""Return a formatted str from the `result`."""
return self._output_format.format(result)
3 changes: 3 additions & 0 deletions lambda_handlers/handlers/mixins/validation_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ class ValidationMixin:
@property
@abstractmethod
def validator(self):
"""Return the validator for events and results."""
pass

def validate_event(self, event, context):
"""Validate the event with `self.validator`, return event and context."""
if self.validator:
transformed_event, transformed_context = self.validator.validate_event(event, context)
event.update(transformed_event)
Expand All @@ -21,6 +23,7 @@ def validate_event(self, event, context):
return event, context

def validate_result(self, result: Dict[str, Any]) -> Dict[str, Any]:
"""Validate and return the result with `self.validator`."""
if self.validator:
return self.validator.validate_result(result)
return result
2 changes: 1 addition & 1 deletion lambda_handlers/validators/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Data validators"""
"""Data schema validators."""

from .jsonschema_validator import JSONSchemaValidator as jsonschema # noqa
from .marshmallow_validator import MarshmallowValidator as marshmallow # noqa
4 changes: 4 additions & 0 deletions lambda_handlers/validators/conftest.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
"""Test utilities and fixtures."""

from typing import Any, Dict, List
from collections import defaultdict

import pytest


def builder(base_class):
"""Return a simple Validator for testing."""
class SimpleSchemaValidator(base_class):

def validate(self, instance: Any, schema: dict):
Expand Down Expand Up @@ -34,4 +37,5 @@ def format_errors(self, errors) -> List[Dict[str, Any]]:

@pytest.fixture
def simple_schema_validator_builder():
"""Return the simple Validator for testing builder function."""
return builder
2 changes: 1 addition & 1 deletion lambda_handlers/validators/jsonschema_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@


class JSONSchemaValidator(Validator):
"""A validator for jsonschema Schemas."""
"""A Validator that uses jsonschema schemas."""

def validate(
self,
Expand Down
3 changes: 2 additions & 1 deletion lambda_handlers/validators/marshmallow_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@


class MarshmallowValidator(Validator):
"""A validator for Marshmallow Schemas."""
"""A Validator that uses Marshmallow schemas."""

def validate(
self,
instance: Any,
Expand Down
81 changes: 78 additions & 3 deletions lambda_handlers/validators/validator.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
"""Base class for Validators."""

from abc import ABC, abstractmethod
from typing import Any, Dict, List, Tuple, Union, Callable
from typing import Any, Dict, List, Tuple, Union
from collections import defaultdict

from lambda_handlers.errors import EventValidationError, ResultValidationError


class Validator(ABC):
"""Base class for Validators.
Parameters
----------
input_schema:
The schema to validate the input data: event and context.
output_schema:
The schema to validate the output data: handler's return value.
"""

def __init__(
self,
Expand All @@ -17,9 +29,34 @@ def __init__(

@property
def schemas(self) -> Dict[str, Any]:
"""The schemas for each section of context."""
return {}

def validate_event(self, event, context) -> Tuple[Any, Any]:
def validate_event(self, event: Any, context: Any) -> Tuple[Any, Any]:
"""Validate `event` against the input_schema.
Parameters
----------
event:
The event data object.
context:
The context data object.
Returns
-------
data: Any
The same as `event` after passing through validation.
context: Any
The validated context in case there is no input_schema, but
the schemas function is used.
Raises
------
ResultValidationError:
In case of validation errors.
"""
if self._input_schema:
data, errors = self.validate(event, self._input_schema)

Expand All @@ -32,6 +69,23 @@ def validate_event(self, event, context) -> Tuple[Any, Any]:
return self._validate_event_contexts(event, context)

def validate_result(self, result: Dict[str, Any]) -> Dict[str, Any]:
"""Validate `result` against the output_schema.
Parameters
----------
result: Dict[str, Any]
The data object.
Returns
-------
data: Dict[str, Any]
The same as `result`.
Raises
------
ResultValidationError:
In case of validation errors.
"""
if not self._output_schema:
return result

Expand Down Expand Up @@ -60,7 +114,7 @@ def _validate_event_contexts(self, event, context) -> Tuple[Dict[str, Any], List
def _validate_many(
self,
target: Dict[str, Any],
definitions: Dict[str, Callable],
definitions: Dict[str, Any],
) -> Tuple[Dict[str, Any], Dict[str, List[Any]]]:

cumulative_errors: Dict[str, List[Any]] = defaultdict(list)
Expand All @@ -81,8 +135,29 @@ def _validate_many(

@abstractmethod
def validate(self, instance: Any, schema: Any) -> Tuple[Any, Union[Dict[str, Any], List[Any]]]:
"""Validate `instance` against `schema`.
Abstract method to be replaced when the specific validation method is chosen.
Parameters
----------
instance:
The data object to be validated.
schema:
The data schema definition.
Returns
-------
transformed_data: Any
The result validated data.
errors: Union[Dict[str, Any], List[Any]]
The validation errors.
"""
pass

@abstractmethod
def format_errors(self, errors: Union[Dict[str, Any], List[Any]]) -> List[Dict[str, Any]]:
"""Re-structure `errors` for output."""
pass

0 comments on commit 79b5d5a

Please sign in to comment.