Skip to content
This repository has been archived by the owner on Feb 21, 2023. It is now read-only.

Type Hints for aioredis #584

Merged
merged 3 commits into from Apr 20, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions .travis.yml
Expand Up @@ -60,6 +60,16 @@ jobs:
- make flake
- <<: *FLAKE
python: "3.7"
- &MYPY
name: mypy
cache: false
python: "3.6"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
python: "3.6"
python: "3.7"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes total sense. Added 3.7 version for Travis-CI job.

install:
- pip install -r tests/requirements.txt
script:
- make mypy
- <<: *MYPY
python: "3.7"
# Run examples Python 3.6, 3.7 and system Redis
- &EXAMPLES
stage: examples
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.txt
Expand Up @@ -27,6 +27,7 @@ Marijn Giesen
Martin <the-panda>
Michael Käufl
Nickolai Novik
Oleg Butuzov
Pau Freixes
Paul Colomiets
Samuel Colvin
Expand Down
4 changes: 4 additions & 0 deletions Makefile
@@ -1,6 +1,7 @@
PYTHON ?= python3
FLAKE ?= flake8
PYTEST ?= pytest
MYPY ?= mypy

REDIS_VERSION ?= "$(shell redis-cli INFO SERVER | sed -n 2p)"
REDIS_TAGS ?= 2.6.17 2.8.22 3.0.7 3.2.8 4.0.11 5.0.1
Expand Down Expand Up @@ -34,6 +35,9 @@ flake:
@echo "Job is not configured to run on $(PYTHON_IMPL); skipped."
endif

mypy:
$(MYPY) aioredis --ignore-missing-imports

test:
$(PYTEST)

Expand Down
5 changes: 4 additions & 1 deletion aioredis/errors.py
@@ -1,3 +1,5 @@
from typing import Optional, Sequence

__all__ = [
'RedisError',
'ProtocolError',
Expand Down Expand Up @@ -28,7 +30,7 @@ class ProtocolError(RedisError):
class ReplyError(RedisError):
"""Raised for redis error replies (-ERR)."""

MATCH_REPLY = None
MATCH_REPLY: Optional[Sequence[str]] = None

def __new__(cls, msg, *args):
for klass in cls.__subclasses__():
Expand All @@ -37,6 +39,7 @@ def __new__(cls, msg, *args):
return super().__new__(cls, msg, *args)



class MaxClientsError(ReplyError):
"""Raised for redis server when the maximum number of client has been
reached."""
Expand Down
38 changes: 20 additions & 18 deletions aioredis/parser.py
@@ -1,23 +1,24 @@
from .errors import ProtocolError, ReplyError
from typing import Optional, Generator, Callable, Iterator

__all__ = [
'Reader', 'PyReader',
]


class PyReader:
"""Pure-Python Redis protocol parser that follows hiredis.Reader
interface (except setmaxbuf/getmaxbuf).
"""
def __init__(self, protocolError=ProtocolError, replyError=ReplyError,
encoding=None):
def __init__(self, protocolError: Callable = ProtocolError,
replyError: Callable = ReplyError,
encoding: Optional[str] = None):
if not callable(protocolError):
raise TypeError("Expected a callable")
if not callable(replyError):
raise TypeError("Expected a callable")
self._parser = Parser(protocolError, replyError, encoding)

def feed(self, data, o=0, l=-1):
def feed(self, data, o: int = 0, l: int = -1):
"""Feed data to parser."""
if l == -1:
l = len(data) - o
Expand All @@ -35,31 +36,33 @@ def gets(self):
"""
return self._parser.parse_one()

def setmaxbuf(self, size):
def setmaxbuf(self, size: Optional[int] ) -> None:
"""No-op."""
pass

def getmaxbuf(self):
def getmaxbuf(self) -> int:
"""No-op."""
return 0


class Parser:
def __init__(self, protocolError, replyError, encoding):
self.buf = bytearray()
self.pos = 0
self.protocolError = protocolError
self.replyError = replyError
self.encoding = encoding
def __init__(self, protocolError: Callable,
replyError: Callable, encoding: Optional[str] ):

self.buf: bytearray = bytearray()
self.pos: int = 0
self.protocolError: Callable = protocolError
self.replyError: Callable = replyError
self.encoding: Optional[str] = encoding
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wont work in Python 3.5

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean variable annotations

self._err = None
self._gen = None
self._gen: Optional[Generator] = None

def waitsome(self, size):
def waitsome(self, size: int) -> Iterator[bool]:
# keep yielding false until at least `size` bytes added to buf.
while len(self.buf) < self.pos+size:
yield False

def waitany(self):
def waitany(self) -> Iterator[bool]:
yield from self.waitsome(len(self.buf) + 1)

def readone(self):
Expand All @@ -69,7 +72,7 @@ def readone(self):
self.pos += 1
return val

def readline(self, size=None):
def readline(self, size: Optional[int] = None):
if size is not None:
if len(self.buf) < size + 2 + self.pos:
yield from self.waitsome(size + 2)
Expand All @@ -96,7 +99,7 @@ def error(self, msg):
self._err = self.protocolError(msg)
return self._err

def parse(self, is_bulk=False):
def parse(self, is_bulk: bool = False):
if self._err is not None:
raise self._err
ctl = yield from self.readone()
Expand Down Expand Up @@ -156,7 +159,6 @@ def parse_one(self):
else:
return False


try:
import hiredis
Reader = hiredis.Reader
Expand Down
1 change: 1 addition & 0 deletions tests/requirements.txt
Expand Up @@ -5,3 +5,4 @@ pytest==4.1.1
pytest-cov==2.6.1
pytest-xdist==1.26.0
async-timeout==3.0.1
mypy