Skip to content

Commit

Permalink
Fix typing of Parser's unbound methods
Browse files Browse the repository at this point in the history
All credit due to "Finite State Machine" on the typing gitter, they're
the one who had the idea of trying to type `self` in case that would
make mypy happy. Which it absolutely does.

This does make that use pattern easier to recommend, as it's fully
typed as well.
  • Loading branch information
masklinn committed Feb 28, 2024
1 parent b9f74ec commit 5595b2b
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 8 deletions.
8 changes: 4 additions & 4 deletions src/ua_parser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,25 +93,25 @@ def __call__(self, ua: str, domains: Domain, /) -> PartialParseResult:
"""
return self.resolver(ua, domains)

def parse(self, ua: str) -> ParseResult:
def parse(self: Resolver, ua: str) -> ParseResult:
"""Convenience method for parsing all domains, and falling back to
default values for all failures.
"""
return self(ua, Domain.ALL).complete()

def parse_user_agent(self, ua: str) -> Optional[UserAgent]:
def parse_user_agent(self: Resolver, ua: str) -> Optional[UserAgent]:
"""Convenience method for parsing the :class:`UserAgent` domain,
falling back to the default value in case of failure.
"""
return self(ua, Domain.USER_AGENT).user_agent

def parse_os(self, ua: str) -> Optional[OS]:
def parse_os(self: Resolver, ua: str) -> Optional[OS]:
"""Convenience method for parsing the :class:`OS` domain, falling back
to the default value in case of failure.
"""
return self(ua, Domain.OS).os

def parse_device(self, ua: str) -> Optional[Device]:
def parse_device(self: Resolver, ua: str) -> Optional[Device]:
"""Convenience method for parsing the :class:`Device` domain, falling
back to the default value in case of failure.
"""
Expand Down
14 changes: 10 additions & 4 deletions tests/test_convenience_parser.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
from ua_parser import Parser, ParseResult, PartialParseResult
from ua_parser import Domain, Parser, ParseResult, PartialParseResult


def resolver(s: str, d: Domain) -> PartialParseResult:
return PartialParseResult(d, None, None, None, s)


def test_parser_utility() -> None:
"""Tests that ``Parser``'s methods to behave as procedural
helpers, for users who may not wish to instantiate a parser or
something.
Sadly the typing doesn't really play nicely with that.
"""
r = Parser.parse(lambda s, d: PartialParseResult(d, None, None, None, s), "a") # type: ignore

r = Parser.parse(resolver, "a")
assert r == ParseResult(None, None, None, "a")

os = Parser.parse_os(resolver, "a")
assert os is None

0 comments on commit 5595b2b

Please sign in to comment.