Skip to content

Commit 93d5f84

Browse files
committed
Add type hints and py.typed marker (PEP 561)
Annotate the whole codebase (client, main GrobidClient, the TEI2LossyJSON and TEI2Markdown converters, the CLIs and the validator) and ship a py.typed marker so type checkers pick up the inline hints. Each module uses 'from __future__ import annotations' so annotations stay lazy and cannot affect runtime behavior (and remain valid on Python 3.8). Packaging: - add grobid_client/py.typed and expose it via package-data and MANIFEST.in - include the grobid_client.format subpackage in the distribution - add a [tool.mypy] section (ignore missing third-party stubs; relax the BeautifulSoup-heavy converter modules whose dynamic API yields false positives) mypy runs clean on the package and the existing test-suite still passes. Closes #71
1 parent 2b0a245 commit 93d5f84

12 files changed

Lines changed: 238 additions & 169 deletions

MANIFEST.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
include Readme.md
1+
include Readme.md
2+
include grobid_client/py.typed

Readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ concurrent processing capabilities for PDF documents, reference strings, and pat
3333
- **Sentence Segmentation**: Layout-aware sentence segmentation capabilities
3434
- **JSON Output**: Convert TEI XML output to structured JSON format with CORD-19-like structure
3535
- **Markdown Output**: Convert TEI XML output to clean Markdown format with structured sections
36+
- **Type Hints**: Ships inline type annotations and a `py.typed` marker (PEP 561) for static type checking
3637

3738
## 📋 Prerequisites
3839

grobid_client/client.py

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
""" Generic API Client """
2+
from __future__ import annotations
3+
24
from copy import deepcopy
35
import json
6+
from typing import Any, Optional, Tuple
7+
48
import requests
59

610
try:
@@ -16,12 +20,17 @@ class ApiClient(object):
1620
service methods, i.e. ``get``, ``post``, ``put`` and ``delete``.
1721
"""
1822

19-
accept_type = "application/xml"
20-
api_base = None
23+
accept_type: str = "application/xml"
24+
api_base: Optional[str] = None
2125

2226
def __init__(
23-
self, base_url, username=None, api_key=None, status_endpoint=None, timeout=60
24-
):
27+
self,
28+
base_url: str,
29+
username: Optional[str] = None,
30+
api_key: Optional[str] = None,
31+
status_endpoint: Optional[str] = None,
32+
timeout: int = 60,
33+
) -> None:
2534
"""Initialise client.
2635
2736
Args:
@@ -37,7 +46,7 @@ def __init__(
3746
self.timeout = timeout
3847

3948
@staticmethod
40-
def encode(request, data):
49+
def encode(request: Any, data: Optional[dict]) -> Any:
4150
"""Add request content data to request body, set Content-type header.
4251
4352
Should be overridden by subclasses if not using JSON encoding.
@@ -58,7 +67,7 @@ def encode(request, data):
5867
return request
5968

6069
@staticmethod
61-
def decode(response):
70+
def decode(response: Any) -> Any:
6271
"""Decode the returned data in the response.
6372
6473
Should be overridden by subclasses if something else than JSON is
@@ -73,9 +82,9 @@ def decode(response):
7382
try:
7483
return response.json()
7584
except ValueError as e:
76-
return e.message
85+
return e.message # type: ignore[attr-defined] # pre-existing (Python 2 style)
7786

78-
def get_credentials(self):
87+
def get_credentials(self) -> dict:
7988
"""Returns parameters to be added to authenticate the request.
8089
8190
This lives on its own to make it easier to re-implement it if needed.
@@ -87,14 +96,14 @@ def get_credentials(self):
8796

8897
def call_api(
8998
self,
90-
method,
91-
url,
92-
headers=None,
93-
params=None,
94-
data=None,
95-
files=None,
96-
timeout=None,
97-
):
99+
method: str,
100+
url: str,
101+
headers: Optional[dict] = None,
102+
params: Optional[dict] = None,
103+
data: Optional[dict] = None,
104+
files: Optional[dict] = None,
105+
timeout: Optional[int] = None,
106+
) -> Tuple[requests.Response, int]:
98107
"""Call API.
99108
100109
This returns object containing data, with error details if applicable.
@@ -130,7 +139,7 @@ def call_api(
130139

131140
return r, r.status_code
132141

133-
def get(self, url, params=None, **kwargs):
142+
def get(self, url: str, params: Optional[dict] = None, **kwargs: Any) -> Tuple[requests.Response, int]:
134143
"""Call the API with a GET request.
135144
136145
Args:
@@ -142,7 +151,7 @@ def get(self, url, params=None, **kwargs):
142151
"""
143152
return self.call_api("GET", url, params=params, **kwargs)
144153

145-
def delete(self, url, params=None, **kwargs):
154+
def delete(self, url: str, params: Optional[dict] = None, **kwargs: Any) -> Tuple[requests.Response, int]:
146155
"""Call the API with a DELETE request.
147156
148157
Args:
@@ -154,7 +163,14 @@ def delete(self, url, params=None, **kwargs):
154163
"""
155164
return self.call_api("DELETE", url, params=params, **kwargs)
156165

157-
def put(self, url, params=None, data=None, files=None, **kwargs):
166+
def put(
167+
self,
168+
url: str,
169+
params: Optional[dict] = None,
170+
data: Optional[dict] = None,
171+
files: Optional[dict] = None,
172+
**kwargs: Any,
173+
) -> Tuple[requests.Response, int]:
158174
"""Call the API with a PUT request.
159175
160176
Args:
@@ -170,7 +186,14 @@ def put(self, url, params=None, data=None, files=None, **kwargs):
170186
"PUT", url, params=params, data=data, files=files, **kwargs
171187
)
172188

173-
def post(self, url, params=None, data=None, files=None, **kwargs):
189+
def post(
190+
self,
191+
url: str,
192+
params: Optional[dict] = None,
193+
data: Optional[dict] = None,
194+
files: Optional[dict] = None,
195+
**kwargs: Any,
196+
) -> Tuple[requests.Response, int]:
174197
"""Call the API with a POST request.
175198
176199
Args:
@@ -186,7 +209,7 @@ def post(self, url, params=None, data=None, files=None, **kwargs):
186209
method="POST", url=url, params=params, data=data, files=files, **kwargs
187210
)
188211

189-
def service_status(self, **kwargs):
212+
def service_status(self, **kwargs: Any) -> Tuple[requests.Response, int]:
190213
"""Call the API to get the status of the service.
191214
192215
Returns:

0 commit comments

Comments
 (0)