Skip to content

Commit

Permalink
Merge c2d9443 into 2b1c7ea
Browse files Browse the repository at this point in the history
  • Loading branch information
jmolinski committed Mar 25, 2019
2 parents 2b1c7ea + c2d9443 commit d23fc2c
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 3 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ Todo:
- methods on models (episode.rate() etc)
- error handling
- http component retries etc
- filters - additional validation
- define all paths & user friendly aliases
- user profile
- docs
Expand Down
24 changes: 23 additions & 1 deletion tests/test_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,37 @@ def test_extended_validator():


def test_filters_validator():
p = Path("a", {}, filters=["query", "genres"])
p = Path("a", {}, filters=["query", "genres", "years", "ratings"])

assert FiltersValidator().validate(path=p) is None
assert FiltersValidator().validate(path=p, query="xyz") is None
assert FiltersValidator().validate(path=p, genres="xyz") is None
assert FiltersValidator().validate(path=p, genres=["xyz", "abc"]) is None
assert FiltersValidator().validate(path=p, years=2015) is None
assert FiltersValidator().validate(path=p, years="2015") is None
assert FiltersValidator().validate(path=p, years="2013-2015") is None
assert FiltersValidator().validate(path=p, ratings="5-100") is None

with pytest.raises(ArgumentError):
FiltersValidator().validate(path=p, languages="xyz")

with pytest.raises(ArgumentError):
FiltersValidator().validate(path=p, query=["abc", "xyz"])

with pytest.raises(ArgumentError):
FiltersValidator().validate(path=p, years="500-2015")

with pytest.raises(ArgumentError):
FiltersValidator().validate(path=p, years="2014-2015-2016")

with pytest.raises(ArgumentError):
FiltersValidator().validate(path=p, years="-2015")

with pytest.raises(ArgumentError):
FiltersValidator().validate(path=p, years="20132015")

with pytest.raises(ArgumentError):
FiltersValidator().validate(path=p, years=0.5)

with pytest.raises(ArgumentError):
FiltersValidator().validate(path=p, ratings="20")
56 changes: 55 additions & 1 deletion trakt/core/paths/validators.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

from typing import Any, Callable, List
import re
from typing import Any, Callable, Dict, List

from trakt.core.abstract import AbstractApi
from trakt.core.exceptions import ArgumentError, NotAuthenticated
Expand All @@ -22,6 +23,14 @@

ALL_FILTERS = SINGLE_FILTERS | MULTI_FILTERS

STATUS_FILTER_VALUES = {
"returning series",
"in production",
"planned",
"canceled",
"ended",
}


class Validator:
def validate(
Expand Down Expand Up @@ -93,6 +102,22 @@ def validate(self, *args: Any, path: Any, **kwargs: Any) -> None:


class FiltersValidator(Validator):
filter_value_validators: Dict[str, Callable[[Any], bool]]

def __init__(self):
self.filter_value_validators = {
"query": lambda s: isinstance(s, str) and s,
"years": self.years_filter_validator,
"genres": lambda g: isinstance(g, str) and g,
"languages": lambda l: isinstance(l, str) and len(l) == 2,
"countries": lambda c: isinstance(c, str) and len(c) == 2,
"runtimes": lambda r: isinstance(r, (int, str)) and int(r) in range(1000),
"ratings": self.ratings_filter_validator,
"certifications": lambda c: isinstance(c, str) and c,
"networks": lambda n: isinstance(n, str) and n,
"status": lambda s: s in STATUS_FILTER_VALUES,
}

def validate(self, *args: Any, path: Any, **kwargs: Any) -> None:
for k in kwargs:
if k in ALL_FILTERS:
Expand All @@ -110,6 +135,8 @@ def _validate_filter_arg(
if filter in MULTI_FILTERS:
self._validate_multi_filter(filter, value)

self._validate_filter_value(filter, value)

def _validate_multi_filter(self, filter: str, value: Any):
if not isinstance(value, (tuple, list, str)):
raise ArgumentError(
Expand All @@ -121,3 +148,30 @@ def _validate_multi_filter(self, filter: str, value: Any):
raise ArgumentError(
f"{filter} filter invalid value (must be str or itarable of str)"
)

def _validate_filter_value(self, filter: str, value: Any):
if not isinstance(value, (list, tuple)):
value = [value]
for v in value:
if not self.filter_value_validators[filter](v):
raise ArgumentError(f"{filter}: {v} is not a valid value")

@staticmethod
def years_filter_validator(years: Any):
years = [years] if isinstance(years, int) else years.split("-")

if len(years) not in {1, 2}:
return False

for y in years:
try:
if int(y) not in range(1800, 2100):
return False
except ValueError:
return False

return True

@staticmethod
def ratings_filter_validator(ratings: Any):
return isinstance(ratings, str) and re.match(r"\d{1,2}-\d{1,3}", ratings)

0 comments on commit d23fc2c

Please sign in to comment.