From febbb107c47a407656ea2f6fdedc87425703e44b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 22:18:57 +0000 Subject: [PATCH] Fix Python 3.9 compatibility: replace pipe union syntax with Union/Optional Co-authored-by: seanthegeek <44679+seanthegeek@users.noreply.github.com> --- parsedmarc/__init__.py | 36 ++++++++++++++++++------------------ parsedmarc/elastic.py | 2 +- parsedmarc/utils.py | 8 ++++---- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/parsedmarc/__init__.py b/parsedmarc/__init__.py index eb6cfab..ea00f5f 100644 --- a/parsedmarc/__init__.py +++ b/parsedmarc/__init__.py @@ -103,11 +103,11 @@ class DateIntervalBucket(TypedDict): class IPAddressInfo(TypedDict, total=False): """Information about an IP address""" ip_address: str - country: NotRequired[str | None] - reverse_dns: NotRequired[str | None] - base_domain: NotRequired[str | None] - type: NotRequired[str | None] - name: NotRequired[str | None] + country: NotRequired[Optional[str]] + reverse_dns: NotRequired[Optional[str]] + base_domain: NotRequired[Optional[str]] + type: NotRequired[Optional[str]] + name: NotRequired[Optional[str]] class AlignmentInfo(TypedDict): @@ -148,8 +148,8 @@ class AuthResults(TypedDict): class Identifiers(TypedDict): """Message identifiers""" header_from: str - envelope_from: str | None - envelope_to: str | None + envelope_from: Optional[str] + envelope_to: Optional[str] class ParsedReportRecord(TypedDict): @@ -165,8 +165,8 @@ class ParsedReportRecord(TypedDict): class ReportMetadata(TypedDict, total=False): """DMARC report metadata""" org_name: str - org_email: NotRequired[str | None] - org_extra_contact_info: NotRequired[str | None] + org_email: NotRequired[Optional[str]] + org_extra_contact_info: NotRequired[Optional[str]] report_id: str begin_date: str end_date: str @@ -195,13 +195,13 @@ class ParsedAggregateReport(TypedDict): class SMTPTLSFailureDetails(TypedDict): """SMTP TLS failure details""" result_type: str - sending_mta_ip: NotRequired[str | None] - receiving_mx_hostname: NotRequired[str | None] - receiving_mx_helo: NotRequired[str | None] - receiving_ip: NotRequired[str | None] + sending_mta_ip: NotRequired[Optional[str]] + receiving_mx_hostname: NotRequired[Optional[str]] + receiving_mx_helo: NotRequired[Optional[str]] + receiving_ip: NotRequired[Optional[str]] failed_session_count: int - additional_information: NotRequired[str | None] - failure_reason_code: NotRequired[str | None] + additional_information: NotRequired[Optional[str]] + failure_reason_code: NotRequired[Optional[str]] class SMTPTLSPolicy(TypedDict): @@ -980,7 +980,7 @@ def extract_report(content: Union[bytes, str, IO[Any]]) -> str: str: The extracted text """ - file_object: BytesIO | IO[Any] + file_object: Union[BytesIO, IO[Any]] try: if isinstance(content, str): try: @@ -1047,7 +1047,7 @@ def parse_aggregate_report_file( aggregate DMARC report Args: - _input (str | bytes | IO): A path to a file, a file like object, or bytes + _input (Union[str, bytes, IO]): A path to a file, a file like object, or bytes offline (bool): Do not query online for geolocation or DNS always_use_local_files (bool): Do not download files reverse_dns_map_path (str): Path to a reverse DNS map file @@ -1723,7 +1723,7 @@ def parse_report_file( file-like object. or bytes Args: - input_ (str | bytes | IO): A path to a file, a file like object, or bytes + input_ (Union[str, bytes, IO]): A path to a file, a file like object, or bytes nameservers (list): A list of one or more nameservers to use (Cloudflare's public DNS resolvers by default) dns_timeout (float): Sets the DNS timeout in seconds diff --git a/parsedmarc/elastic.py b/parsedmarc/elastic.py index aad982c..4541356 100644 --- a/parsedmarc/elastic.py +++ b/parsedmarc/elastic.py @@ -278,7 +278,7 @@ def set_hosts( Sets the Elasticsearch hosts to use Args: - hosts (str | list[str]): A single hostname or URL, or list of hostnames or URLs + hosts (Union[str, list[str]]): A single hostname or URL, or list of hostnames or URLs use_ssl (bool): Use an HTTPS connection to the server ssl_cert_path (str): Path to the certificate chain username (str): The username to use for authentication diff --git a/parsedmarc/utils.py b/parsedmarc/utils.py index 474836d..c40b5fc 100644 --- a/parsedmarc/utils.py +++ b/parsedmarc/utils.py @@ -68,10 +68,10 @@ class DownloadError(RuntimeError): class EmailAddress(TypedDict): """Parsed email address information""" - display_name: str | None + display_name: Optional[str] address: str - local: str | None - domain: str | None + local: Optional[str] + domain: Optional[str] def decode_base64(data: str) -> bytes: @@ -558,7 +558,7 @@ def is_mbox(path: str) -> bool: return _is_mbox -def is_outlook_msg(content: bytes | Any) -> bool: +def is_outlook_msg(content: Union[bytes, Any]) -> bool: """ Checks if the given content is an Outlook msg OLE/MSG file