Skip to content

Commit 4a1ccc6

Browse files
committed
Added MyPy configuration in setup.cfg and added a MyPy job to CI
1 parent a4ed01d commit 4a1ccc6

File tree

6 files changed

+44
-16
lines changed

6 files changed

+44
-16
lines changed

.github/workflows/ci.yml

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,29 @@ jobs:
2626
- name: Check
2727
run: python -m flake8
2828

29+
mypy:
30+
name: MyPy
31+
runs-on: ubuntu-latest
32+
steps:
33+
- uses: actions/checkout@v4.1.1
34+
- name: Setup Build Tools
35+
run: sudo apt-get install -y libkrb5-dev krb5-user krb5-kdc krb5-admin-server krb5-multidev
36+
- name: Set Up Python
37+
uses: actions/setup-python@v5.0.0
38+
with:
39+
python-version: '3.13'
40+
- name: Install dependencies
41+
run: |
42+
python -m pip install -U pip
43+
python -m pip install mypy .[all]
44+
- name: Check
45+
run: python -m mypy --install-types --non-interactive
46+
2947
test:
3048
name: Test
31-
needs: flake8
49+
needs:
50+
- flake8
51+
- mypy
3252
runs-on: ubuntu-latest
3353
strategy:
3454
matrix:

HISTORY.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ History
44
FUTURE: TBD
55
-----------
66
- Added ``py.typed`` marker to declare this package supports typing (closes #50)
7+
- Added MyPy configuration in `setup.cfg` and added a MyPy job to CI
78

89
0.5.0: 2025-09-08
910
-----------------

httpx_gssapi/exceptions.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@
55
This module contains the set of exceptions.
66
77
"""
8+
9+
from typing import Optional
10+
811
from httpx import RequestError, Request, Response
912

1013

1114
class MutualAuthenticationError(RequestError):
1215
"""Mutual Authentication Error"""
1316

1417
def __init__(self, *,
15-
request: Request = None,
18+
request: Optional[Request] = None,
1619
response: Response):
1720
self.response = response
1821
super().__init__(

httpx_gssapi/gssapi_.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,9 @@
4242
def _negotiate_value(response: Response) -> Optional[bytes]:
4343
"""Extracts the gssapi authentication token from the appropriate header"""
4444
authreq = response.headers.get('www-authenticate', None)
45-
if authreq:
46-
match_obj = _find_auth(authreq)
47-
if match_obj:
48-
return b64decode(match_obj.group(1))
45+
if authreq and (match := _find_auth(authreq)):
46+
return b64decode(match.group(1))
47+
return None
4948

5049

5150
def _sanitize_response(response: Response):
@@ -139,10 +138,10 @@ class HTTPSPNEGOAuth(Auth):
139138

140139
def __init__(self,
141140
mutual_authentication: int = DISABLED,
142-
target_name: Optional[str] = "HTTP",
141+
target_name: Optional[Union[str, gssapi.Name]] = "HTTP",
143142
delegate: bool = False,
144143
opportunistic_auth: bool = False,
145-
creds: gssapi.Credentials = None,
144+
creds: Optional[gssapi.Credentials] = None,
146145
mech: Optional[Union[bytes, gssapi.OID]] = SPNEGO,
147146
sanitize_mutual_error_response: bool = True):
148147
self.mutual_authentication = mutual_authentication
@@ -165,7 +164,7 @@ def auth_flow(self, request: Request) -> FlowGen:
165164

166165
def handle_response(self,
167166
response: Response,
168-
ctx: SecurityContext = None) -> FlowGen:
167+
ctx: Optional[SecurityContext] = None) -> FlowGen:
169168
num_401s = 0
170169
while response.status_code == 401 and num_401s < 2:
171170
num_401s += 1
@@ -235,7 +234,7 @@ def handle_mutual_auth(self, response: Response, ctx: SecurityContext):
235234
@_handle_gsserror(gss_stage='stepping', result=_gss_to_spnego_error)
236235
def set_auth_header(self,
237236
request: Request,
238-
response: Response = None) -> SecurityContext:
237+
response: Optional[Response] = None) -> SecurityContext:
239238
"""
240239
Create a new security context, generate the GSSAPI authentication
241240
token, and insert it into the request header. The new security context
@@ -286,17 +285,17 @@ def _make_context(self, request: Request) -> SecurityContext:
286285
used if it isn't included in :py:attr:`target_name`.
287286
"""
288287
name = self.target_name
289-
if type(name) != gssapi.Name: # type(name) is str
290-
if '@' not in name:
288+
if type(name) != gssapi.Name: # None/str
289+
if isinstance(name, str) and '@' not in name:
291290
name += f"@{request.url.host}"
292291
name = gssapi.Name(name, gssapi.NameType.hostbased_service)
293292

294293
return SecurityContext(
295294
usage="initiate",
296-
flags=self._gssflags,
295+
flags=self._gssflags, # type: ignore[arg-type] # list[int] is fine
297296
name=name,
298297
creds=self.creds,
299-
mech=self.mech,
298+
mech=self.mech, # type: ignore[arg-type] # bytes are fine
300299
)
301300

302301
@property

setup.cfg

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ exclude =
7575
doc,
7676
httpx_gssapi/_version.py
7777

78+
[mypy]
79+
packages =
80+
httpx_gssapi,
81+
tests
82+
7883
[tox:tox]
7984
envlist = py36, py37, py38, py39, py310
8085

tests/conftest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from http.server import HTTPServer, BaseHTTPRequestHandler
1111

1212
import pytest
13-
import k5test
13+
import k5test # type: ignore[import-untyped]
1414

1515
import gssapi.exceptions
1616

@@ -86,7 +86,7 @@ def start_http_server(realm: k5test.K5Realm,
8686

8787
with HTTPServer(server_address=(host, port),
8888
RequestHandlerClass=KrbRequestHandler) as httpd:
89-
httpd.krb5_realm = realm
89+
httpd.krb5_realm = realm # type: ignore[attr-defined]
9090
httpd.serve_forever()
9191

9292

0 commit comments

Comments
 (0)