Skip to content

Commit 47ede61

Browse files
mikethemandi
andauthored
feat: add type hints (#130)
* refactor: replace deprecated function names The camelCase functions have been marked as deprecated. Replace with equivalent snake_case functions. Move `set_name()` assignments to their parent `Word` when possible, to address a type error since `set_results_name()` emits a `ParserElement`, not a `Word`. Signed-off-by: Mike Fiedler <[email protected]> * feat: add type hints - Add type hint to the one public interface for user agent parsing. - Add testing step to CI - Include type marker in package - Set classifier metadata Signed-off-by: Mike Fiedler <[email protected]> --------- Signed-off-by: Mike Fiedler <[email protected]> Co-authored-by: Dustin Ingram <[email protected]>
1 parent 63ec25d commit 47ede61

File tree

6 files changed

+35
-30
lines changed

6 files changed

+35
-30
lines changed

.github/workflows/test.yml

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ jobs:
1515
run: python -m pip install --upgrade pip setuptools wheel
1616
- name: Install dependencies
1717
run: python -m pip install -r requirements.txt
18+
- name: Install lint dependencies
19+
run: python -m pip install --upgrade mypy
20+
- name: Lint
21+
run: python -m mypy -p linehaul
1822
- name: Install test dependencies
1923
run: python -m pip install pytest pretend hypothesis pyaml
2024
- name: Test

linehaul/events/parser.py

+26-29
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import cattr
2323

2424
from pyparsing import Literal as L, Word, Optional as OptionalItem
25-
from pyparsing import printables as _printables, restOfLine
25+
from pyparsing import printables as _printables, rest_of_line
2626
from pyparsing import ParseException
2727

2828
from linehaul.ua import UserAgent, parser as user_agents
@@ -44,11 +44,11 @@ class UnparseableEvent(Exception):
4444
pass
4545

4646

47-
class NullValue:
47+
class _NullValue:
4848
pass
4949

5050

51-
NullValue = NullValue()
51+
NullValue = _NullValue()
5252

5353

5454
printables = "".join(set(_printables + " " + "\t") - {"|", "@"})
@@ -58,29 +58,26 @@ class NullValue:
5858
AT = L("@").suppress()
5959

6060
NULL = L("(null)")
61-
NULL.setParseAction(lambda s, l, t: NullValue)
61+
NULL.set_parse_action(lambda s, l, t: NullValue)
6262

63-
TIMESTAMP = Word(printables)
64-
TIMESTAMP = TIMESTAMP.setResultsName("timestamp")
65-
TIMESTAMP.setName("Timestamp")
63+
TIMESTAMP = Word(printables).set_name("Timestamp")
64+
TIMESTAMP = TIMESTAMP.set_results_name("timestamp")
6665

67-
COUNTRY_CODE = Word(printables)
68-
COUNTRY_CODE = COUNTRY_CODE.setResultsName("country_code")
69-
COUNTRY_CODE.setName("Country Code")
66+
COUNTRY_CODE = Word(printables).set_name("Country Code")
67+
COUNTRY_CODE = COUNTRY_CODE.set_results_name("country_code")
7068

71-
URL = Word(printables)
72-
URL = URL.setResultsName("url")
73-
URL.setName("URL")
69+
URL = Word(printables).set_name("URL")
70+
URL = URL.set_results_name("url")
7471

7572
REQUEST = TIMESTAMP + PIPE + OptionalItem(COUNTRY_CODE) + PIPE + URL
7673

7774
PROJECT_NAME = NULL | Word(printables)
78-
PROJECT_NAME = PROJECT_NAME.setResultsName("project_name")
79-
PROJECT_NAME.setName("Project Name")
75+
PROJECT_NAME = PROJECT_NAME.set_results_name("project_name")
76+
PROJECT_NAME.set_name("Project Name")
8077

8178
VERSION = NULL | Word(printables)
82-
VERSION = VERSION.setResultsName("version")
83-
VERSION.setName("Version")
79+
VERSION = VERSION.set_results_name("version")
80+
VERSION.set_name("Version")
8481

8582
PACKAGE_TYPE = NULL | (
8683
L("sdist")
@@ -92,34 +89,34 @@ class NullValue:
9289
| L("bdist_rpm")
9390
| L("bdist_wininst")
9491
)
95-
PACKAGE_TYPE = PACKAGE_TYPE.setResultsName("package_type")
96-
PACKAGE_TYPE.setName("Package Type")
92+
PACKAGE_TYPE = PACKAGE_TYPE.set_results_name("package_type")
93+
PACKAGE_TYPE.set_name("Package Type")
9794

9895
PROJECT = PROJECT_NAME + PIPE + VERSION + PIPE + PACKAGE_TYPE
9996

10097
TLS_PROTOCOL = NULL | Word(printables)
101-
TLS_PROTOCOL = TLS_PROTOCOL.setResultsName("tls_protocol")
102-
TLS_PROTOCOL.setName("TLS Protocol")
98+
TLS_PROTOCOL = TLS_PROTOCOL.set_results_name("tls_protocol")
99+
TLS_PROTOCOL.set_name("TLS Protocol")
103100

104101
TLS_CIPHER = NULL | Word(printables)
105-
TLS_CIPHER = TLS_CIPHER.setResultsName("tls_cipher")
106-
TLS_CIPHER.setName("TLS Cipher")
102+
TLS_CIPHER = TLS_CIPHER.set_results_name("tls_cipher")
103+
TLS_CIPHER.set_name("TLS Cipher")
107104

108105
TLS = TLS_PROTOCOL + PIPE + TLS_CIPHER
109106

110-
USER_AGENT = restOfLine
111-
USER_AGENT = USER_AGENT.setResultsName("user_agent")
112-
USER_AGENT.setName("UserAgent")
107+
USER_AGENT = rest_of_line
108+
USER_AGENT = USER_AGENT.set_results_name("user_agent")
109+
USER_AGENT.set_name("UserAgent")
113110

114111
V1_HEADER = OptionalItem(L("1").suppress() + AT)
115112

116113
MESSAGE_v1 = V1_HEADER + REQUEST + PIPE + PROJECT + PIPE + USER_AGENT
117-
MESSAGE_v1.leaveWhitespace()
114+
MESSAGE_v1.leave_whitespace()
118115

119116
V2_HEADER = L("2").suppress() + AT
120117

121118
MESSAGE_v2 = V2_HEADER + REQUEST + PIPE + TLS + PIPE + PROJECT + PIPE + USER_AGENT
122-
MESSAGE_v2.leaveWhitespace()
119+
MESSAGE_v2.leave_whitespace()
123120

124121
V3_HEADER = L("download")
125122
MESSAGE_v3 = (
@@ -204,7 +201,7 @@ def _value_or_none(value):
204201

205202
def parse(message):
206203
try:
207-
parsed = MESSAGE.parseString(message, parseAll=True)
204+
parsed = MESSAGE.parse_string(message, parseAll=True)
208205
except ParseException as exc:
209206
raise UnparseableEvent("{!r} {}".format(message, exc)) from None
210207

linehaul/py.typed

Whitespace-only changes.

linehaul/ua/parser.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ def BrowserUserAgent():
333333
)
334334

335335

336-
def parse(user_agent):
336+
def parse(user_agent: str) -> UserAgent | None:
337337
try:
338338
return cattr.structure(_parser(user_agent), UserAgent)
339339
except UnableToParse:

pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ classifiers = [
1919
"Programming Language :: Python :: 3",
2020
"Programming Language :: Python :: 3.11",
2121
"Programming Language :: Python :: 3 :: Only",
22+
"Typing :: Typed",
2223
]
2324

2425
dependencies = [

setup.cfg

+3
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
[options]
22
packages = find:
3+
4+
[options.package_data]
5+
* = py.typed

0 commit comments

Comments
 (0)