Skip to content

Commit

Permalink
Merge pull request #16 from d5h-foss/test-with-min-deps
Browse files Browse the repository at this point in the history
Add tests with minimum versions of dependencies, and fix a few issues
  • Loading branch information
d5h authored Apr 24, 2022
2 parents 33016b0 + 6f5ab4b commit 8ecd259
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 16 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ jobs:
with:
python-version: '3.8'
architecture: x64
- run: pip install nox==2020.5.24
- run: pip install poetry==1.0.9
- run: pip install nox==2020.5.24 toml==0.10.2 poetry==1.0.9
- run: nox --sessions tests-3.8 coverage
env:
CODECOV_TOKEN: ${{secrets.CODECOV_TOKEN}}
13 changes: 13 additions & 0 deletions .github/workflows/mindeps.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
name: Minimum Dependencies
on: [push, pull_request]
jobs:
mindeps:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v1
with:
python-version: '3.6'
architecture: x64
- run: pip install nox==2020.5.24 toml==0.10.2 poetry==1.0.9
- run: nox --sessions mindeps
3 changes: 1 addition & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ jobs:
with:
python-version: '3.8'
architecture: x64
- run: pip install nox==2020.5.24
- run: pip install poetry==1.0.9
- run: pip install nox==2020.5.24 toml==0.10.2 poetry==1.0.9
- run: nox
- run: poetry build
- run: poetry publish --username=__token__ --password=${{secrets.PYPI_TOKEN}}
3 changes: 1 addition & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,5 @@ jobs:
with:
python-version: ${{matrix.python-version}}
architecture: x64
- run: pip install nox==2020.5.24
- run: pip install poetry==1.0.9
- run: pip install nox==2020.5.24 toml==0.10.2 poetry==1.0.9
- run: nox
36 changes: 36 additions & 0 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
from contextlib import contextmanager
from pathlib import Path
import tempfile
from typing import List
from uuid import uuid4

import nox
import toml


nox.options.sessions = "lint", "mypy", "safety", "tests", "xdoctest"
Expand Down Expand Up @@ -98,6 +100,14 @@ def safety(session):
session.run("safety", "check", f"--file={requirements}", "--full-report")


@nox.session(python="3.6")
def mindeps(session):
"""Run test with minimum versions of dependencies."""
deps = _parse_minimum_dependency_versions()
session.install(*deps)
session.run("pytest", env={"PYTHONPATH": "src"})


def install_with_constraints(session, *args, **kwargs):
"""Install packages constrained by Poetry's lock file."""
with _temp_file() as requirements:
Expand All @@ -124,3 +134,29 @@ def _temp_file():
path.unlink()
except FileNotFoundError:
pass


def _parse_minimum_dependency_versions() -> List[str]:
pyproj = toml.load("pyproject.toml")
dependencies = pyproj["tool"]["poetry"]["dependencies"]
dev_dependencies = pyproj["tool"]["poetry"]["dev-dependencies"]
min_deps = []

for deps in (dependencies, dev_dependencies):
for dep, constraint in deps.items():
if dep == "python":
continue

if not isinstance(constraint, str):
constraint = constraint["version"]

if constraint.startswith("^") or constraint.startswith("~"):
version = constraint[1:]
elif constraint.startswith(">="):
version = constraint[2:]
else:
version = constraint

min_deps.append(f"{dep}=={version}")

return min_deps
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "grpc-interceptor"
version = "0.14.0"
version = "0.14.1"
description = "Simplifies gRPC interceptors"
license = "MIT"
readme = "README.md"
Expand All @@ -12,7 +12,7 @@ documentation = "https://grpc-interceptor.readthedocs.io"

[tool.poetry.dependencies]
python = "^3.6"
grpcio = "^1.8.0"
grpcio = "^1.8.1"
protobuf = {version = ">=3.6.0", optional = true}

[tool.poetry.extras]
Expand Down
2 changes: 1 addition & 1 deletion src/grpc_interceptor/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class _ClientCallDetailsFields(NamedTuple):
metadata: Optional[Sequence[Tuple[str, Union[str, bytes]]]]
credentials: Optional[grpc.CallCredentials]
wait_for_ready: Optional[bool]
compression: Optional[grpc.Compression]
compression: Any # Type added in grpcio 1.23.0


class ClientCallDetails(_ClientCallDetailsFields, grpc.ClientCallDetails):
Expand Down
4 changes: 2 additions & 2 deletions src/grpc_interceptor/exception_to_status.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""ExceptionToStatusInterceptor catches GrpcException and sets the gRPC context."""

from contextlib import contextmanager
from typing import Any, Callable, Generator, Iterable, Iterator, NoReturn, Optional
from typing import Any, Callable, Generator, Iterable, Iterator, Optional

import grpc

Expand Down Expand Up @@ -62,7 +62,7 @@ def handle_exception(
request_or_iterator: Any,
context: grpc.ServicerContext,
method_name: str,
) -> NoReturn:
) -> None:
"""Override this if extending ExceptionToStatusInterceptor.
This will get called when an exception is raised while handling the RPC.
Expand Down
18 changes: 13 additions & 5 deletions src/grpc_interceptor/server.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Base class for server-side interceptors."""

import abc
from typing import Any, Callable, NamedTuple, Tuple
from typing import Any, Callable, Tuple

import grpc

Expand Down Expand Up @@ -84,7 +84,7 @@ def _get_factory_and_method(
raise RuntimeError("RPC handler implementation does not exist")


class MethodName(NamedTuple):
class MethodName:
"""Represents a gRPC method name.
gRPC methods are defined by three parts, represented by the three attributes.
Expand All @@ -99,9 +99,17 @@ class MethodName(NamedTuple):
method: This is the method name. (e.g., `rpc Search(...) returns (...);`).
"""

package: str
service: str
method: str
def __init__(self, package: str, service: str, method: str):
self.package = package
self.service = service
self.method = method

def __repr__(self) -> str:
"""Object-like representation."""
return (
f"MethodName(package='{self.package}', service='{self.service}',"
f" method='{self.method}')"
)

@property
def fully_qualified_service(self):
Expand Down

0 comments on commit 8ecd259

Please sign in to comment.