Skip to content

Commit

Permalink
Codify CI tasks and improve typing
Browse files Browse the repository at this point in the history
  • Loading branch information
icgood committed Mar 19, 2022
1 parent 42a5e22 commit 67b6ad6
Show file tree
Hide file tree
Showing 81 changed files with 614 additions and 327 deletions.
6 changes: 0 additions & 6 deletions .github/release-drafter.yml

This file was deleted.

22 changes: 8 additions & 14 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,15 @@ jobs:
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel coveralls
python -m pip install --upgrade -r requirements-dev.txt
- name: Lint with flake8
- name: Install build tools
run: |
flake8 pymap test
- name: Type checking with mypy
python -m pip install --upgrade pip setuptools wheel invoke coveralls
- name: Install package and dependencies
run: |
mypy pymap test
- name: Test with pytest
invoke install
- name: Run test suites, type checks, and linters
run: |
py.test --cov=pymap
invoke validate
- name: Report test coverage to Coveralls
if: success()
env:
Expand All @@ -53,9 +49,7 @@ jobs:
python-version: '3.10'
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install --upgrade -r requirements-dev.txt
python -m pip install --upgrade -r doc/requirements.txt
python -m pip install --upgrade pip setuptools wheel invoke
- name: Build the Sphinx documentation
run: |
make -C doc html
invoke install doc.install doc.build
10 changes: 4 additions & 6 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
uses: actions/setup-python@v2
with:
python-version: '3.10'
- name: Install dependencies
- name: Install build tools
run: |
python -m pip install --upgrade pip setuptools wheel twine
- name: Build and publish
Expand All @@ -36,14 +36,12 @@ jobs:
uses: actions/setup-python@v2
with:
python-version: '3.10'
- name: Install dependencies
- name: Install build tools
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install --upgrade -r requirements-dev.txt
python -m pip install --upgrade -r doc/requirements.txt
python -m pip install --upgrade pip setuptools wheel invoke
- name: Build the Sphinx documentation
run: |
make -C doc html
invoke install doc.install doc.build
- name: Deploy to GitHub Pages
if: success()
uses: peaceiris/actions-gh-pages@v3
Expand Down
14 changes: 0 additions & 14 deletions .github/workflows/release-drafter.yml

This file was deleted.

1 change: 0 additions & 1 deletion doc/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
sphinx
sphinx-autodoc-typehints
cloud_sptheme
15 changes: 14 additions & 1 deletion doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
'sphinx.ext.intersphinx',
'sphinx.ext.napoleon',
'sphinx.ext.githubpages',
'sphinx_autodoc_typehints',
'sphinx.ext.viewcode',
]

# Add any paths that contain templates here, relative to this directory.
Expand All @@ -70,10 +70,23 @@
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
if csp.is_cloud_theme(html_theme):
html_theme_options = {
'borderless_decor': True,
'sidebarwidth': '3in',
'hyphenation_language': 'en',
}

# -- Extension configuration -------------------------------------------------

autodoc_member_order = 'bysource'
autodoc_default_flags = ['show-inheritance']
autodoc_typehints = 'description'
autodoc_typehints_format = 'short'
napoleon_numpy_docstring = False

# -- Options for intersphinx extension ---------------------------------------
Expand Down
3 changes: 0 additions & 3 deletions doc/source/pymap.bytes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,3 @@

.. automodule:: pymap.bytes
:members:

.. automodule:: pymap.bytes.rev
:members:
6 changes: 3 additions & 3 deletions pymap/admin/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
__all__ = ['get_unimplemented_error', 'get_incompatible_version_error']


def get_unimplemented_error(*, domain: str = None, **metadata: str) \
def get_unimplemented_error(*, domain: str | None = None, **metadata: str) \
-> GRPCError:
"""Build a :exc:`~grpclib.exceptions.GRPCError` exception for an
operation that is not implemented by the server.
Expand All @@ -23,8 +23,8 @@ def get_unimplemented_error(*, domain: str = None, **metadata: str) \


def get_incompatible_version_error(client_version: str, server_version: str, *,
domain: str = None, **metadata: str) \
-> GRPCError:
domain: str | None = None,
**metadata: str) -> GRPCError:
"""Build a :exc:`~grpclib.exceptions.GRPCError` exception for an
incompatible version error.
Expand Down
8 changes: 5 additions & 3 deletions pymap/backend/dict/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ def status(self) -> HealthStatus:

@classmethod
def add_subparser(cls, name: str, subparsers: Any) -> ArgumentParser:
parser = subparsers.add_parser(name, help='in-memory backend')
parser: ArgumentParser = subparsers.add_parser(
name, help='in-memory backend')
parser.add_argument('--demo-data', action='store_true',
help='load initial demo data')
parser.add_argument('--demo-user', default='demouser',
Expand All @@ -84,7 +85,7 @@ class Config(IMAPConfig):
def __init__(self, args: Namespace, *, demo_data: bool,
demo_user: str, demo_password: str,
demo_data_resource: str = __name__,
admin_key: bytes = None, **extra: Any) -> None:
admin_key: bytes | None = None, **extra: Any) -> None:
admin_key = admin_key or token_bytes()
super().__init__(args, hash_context=Cleartext(), admin_key=admin_key,
**extra)
Expand Down Expand Up @@ -206,7 +207,8 @@ def __init__(self, name: str, login: Login, role: str | None) -> None:
def name(self) -> str:
return self._name

async def new_token(self, *, expiration: datetime = None) -> str | None:
async def new_token(self, *, expiration: datetime | None = None) \
-> str | None:
token_id = uuid.uuid4().hex
token_key = token_bytes()
self.login.tokens_dict[token_id] = (self.name, token_key)
Expand Down
12 changes: 7 additions & 5 deletions pymap/backend/dict/mailbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,19 @@ class Message(BaseMessage):

def __init__(self, uid: int, internal_date: datetime,
permanent_flags: Iterable[Flag], *, expunged: bool = False,
email_id: ObjectId = None, thread_id: ObjectId = None,
recent: bool = False, content: MessageContent = None) -> None:
email_id: ObjectId | None = None,
thread_id: ObjectId | None = None,
recent: bool = False,
content: MessageContent | None = None) -> None:
super().__init__(uid, internal_date, permanent_flags,
expunged=expunged, email_id=email_id,
thread_id=thread_id)
self._recent = recent
self._content = content

@classmethod
def copy(cls, msg: Message, *, uid: int = None, recent: bool = False,
expunged: bool = False) -> Message:
def copy(cls, msg: Message, *, uid: int | None = None,
recent: bool = False, expunged: bool = False) -> Message:
if uid is None:
uid = msg.uid
return cls(uid, msg.internal_date, msg.permanent_flags,
Expand Down Expand Up @@ -220,7 +222,7 @@ def selected_set(self) -> SelectedSet:
return self._selected_set

async def update_selected(self, selected: SelectedMailbox, *,
wait_on: Event = None) -> SelectedMailbox:
wait_on: Event | None = None) -> SelectedMailbox:
if wait_on is not None:
either_event = wait_on.or_event(self._updated)
await either_event.wait()
Expand Down
8 changes: 4 additions & 4 deletions pymap/backend/mailbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from abc import abstractmethod
from collections.abc import Iterable, Sequence, AsyncIterable
from typing import TypeVar, Protocol
from typing import TypeVar, Protocol, Any

from pymap.concurrent import Event
from pymap.flags import FlagOp
Expand All @@ -19,11 +19,11 @@
'MailboxDataInterface', 'MailboxSetInterface']

#: Type variable with an upper bound of :class:`MailboxDataInterface`.
MailboxDataT = TypeVar('MailboxDataT', bound='MailboxDataInterface')
MailboxDataT = TypeVar('MailboxDataT', bound='MailboxDataInterface[Any]')

#: Covariant type variable with an upper bound of
#: :class:`MailboxDataInterface`.
MailboxDataT_co = TypeVar('MailboxDataT_co', bound='MailboxDataInterface',
MailboxDataT_co = TypeVar('MailboxDataT_co', bound='MailboxDataInterface[Any]',
covariant=True)


Expand Down Expand Up @@ -71,7 +71,7 @@ def selected_set(self) -> SelectedSet:

@abstractmethod
async def update_selected(self, selected: SelectedMailbox, *,
wait_on: Event = None) -> SelectedMailbox:
wait_on: Event | None = None) -> SelectedMailbox:
"""Populates and returns the selected mailbox object with the state
needed to discover updates.
Expand Down
7 changes: 4 additions & 3 deletions pymap/backend/maildir/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ def status(self) -> HealthStatus:

@classmethod
def add_subparser(cls, name: str, subparsers: Any) -> ArgumentParser:
parser = subparsers.add_parser(name, help='on-disk backend')
parser: ArgumentParser = subparsers.add_parser(
name, help='on-disk backend')
parser.add_argument('users_file', help='path the the users file')
parser.add_argument('--base-dir', metavar='DIR',
help='base directory for mailbox relative paths')
Expand Down Expand Up @@ -273,7 +274,7 @@ def __init__(self, config: Config, name: str, metadata: UserMetadata,
def name(self) -> str:
return self._name

async def new_token(self, *, expiration: datetime = None) -> None:
async def new_token(self, *, expiration: datetime | None = None) -> None:
return None

@asynccontextmanager
Expand All @@ -284,7 +285,7 @@ async def new_session(self) -> AsyncIterator[Session]:
filter_set = FilterSet(layout.path)
yield Session(self.name, config, mailbox_set, filter_set)

def _load_maildir(self) -> tuple[Maildir, MaildirLayout]:
def _load_maildir(self) -> tuple[Maildir, MaildirLayout[Any]]:
full_path = os.path.join(self.config.base_dir, self.mailbox_path)
layout = MaildirLayout.get(full_path, self.config.layout, Maildir)
create = not os.path.exists(full_path)
Expand Down
8 changes: 5 additions & 3 deletions pymap/backend/maildir/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager, AbstractAsyncContextManager
from tempfile import NamedTemporaryFile
from typing import TypeVar, Generic, IO
from typing import TypeVar, Generic, Any, IO

from pymap.concurrent import FileLock

Expand Down Expand Up @@ -152,7 +152,8 @@ async def __aenter__(self) -> _RT:
self._obj = obj = func(base_dir)
return obj

async def __aexit__(self, exc_type, exc_val, exc_tb) -> bool:
async def __aexit__(self, exc_type: Any, exc_val: Any,
exc_tb: Any) -> bool:
return False


Expand Down Expand Up @@ -190,7 +191,8 @@ def _write_obj(self) -> None:
raise RuntimeError() # Context manager not entered.
obj.file_write()

async def __aexit__(self, exc_type, exc_val, exc_tb) -> bool:
async def __aexit__(self, exc_type: Any, exc_val: Any,
exc_tb: Any) -> bool:
try:
if exc_type:
if issubclass(exc_type, NoChanges):
Expand Down
17 changes: 10 additions & 7 deletions pymap/backend/maildir/mailbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from collections.abc import Iterable, AsyncIterable
from datetime import datetime
from mailbox import Maildir as _Maildir, MaildirMessage
from typing import Final, Literal
from typing import Final, Any, Literal

from pymap.concurrent import Event, ReadWriteLock
from pymap.context import subsystem
Expand Down Expand Up @@ -129,9 +129,11 @@ class Message(BaseMessage):

def __init__(self, uid: int, internal_date: datetime,
permanent_flags: Iterable[Flag], *, expunged: bool = False,
email_id: ObjectId = None, thread_id: ObjectId = None,
recent: bool = False, maildir: Maildir = None,
key: str = None) -> None:
email_id: ObjectId | None = None,
thread_id: ObjectId | None = None,
recent: bool = False,
maildir: Maildir | None = None,
key: str | None = None) -> None:
super().__init__(uid, internal_date, permanent_flags,
expunged=expunged, email_id=email_id,
thread_id=thread_id)
Expand Down Expand Up @@ -247,7 +249,7 @@ async def _get_maildir_msg(self, uid: int) \
return record, maildir_msg

async def update_selected(self, selected: SelectedMailbox, *,
wait_on: Event = None) -> SelectedMailbox:
wait_on: Event | None = None) -> SelectedMailbox:
if wait_on is not None:
await wait_on.wait(timeout=1.0)
all_messages = [msg async for msg in self.messages()]
Expand Down Expand Up @@ -360,7 +362,7 @@ async def delete(self, uids: Iterable[int]) -> None:
async with UidList.with_read(self._path) as uidl:
records = uidl.get_all(uids)
async with self.messages_lock.write_lock():
for uid, rec in records.items():
for rec in records.values():
try:
self._maildir.remove(rec.key)
except (KeyError, FileNotFoundError):
Expand Down Expand Up @@ -457,7 +459,8 @@ async def _get_keys(self) -> dict[str, str]:

class MailboxSet(MailboxSetInterface[MailboxData]):

def __init__(self, maildir: Maildir, layout: MaildirLayout) -> None:
def __init__(self, maildir: Maildir,
layout: MaildirLayout[Any]) -> None:
super().__init__()
self._layout = layout
self._inbox_maildir = maildir
Expand Down
2 changes: 1 addition & 1 deletion pymap/backend/maildir/uidlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class UidList(FileWriteable):
LOCK_FILE: ClassVar[str] = 'dovecot-uidlist.lock'

def __init__(self, base_dir: str, uid_validity: int,
next_uid: int, global_uid: bytes = None) -> None:
next_uid: int, global_uid: bytes | None = None) -> None:
super().__init__()
self._base_dir = base_dir
self.uid_validity = uid_validity
Expand Down

0 comments on commit 67b6ad6

Please sign in to comment.