Skip to content

Commit 41745c4

Browse files
bmosshaunagm
andauthored
Remove end-of-support python 3.9 (#1618)
* remove python 3.9 support * resolve pre-commit ruff legacy alias warning * ruff check auto fixes (updates syntax to python 3.10+) * ruff format * remove old myst parser only needed for python <3.10 * Remove 3.9 from release.yml action matrix * Update urllib3 version in requirements.txt Consolidate urllib3 version specification for compatibility. * update google docs to 3.10+ syntax * ruff check --fix --------- Co-authored-by: Shauna Gordon-McKeon <shaunagm@gmail.com>
1 parent 1a17263 commit 41745c4

40 files changed

+269
-311
lines changed

.github/workflows/python-checks.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ jobs:
1919
fail-fast: false
2020
matrix:
2121
python-version:
22-
- '3.9'
2322
- '3.10'
2423
- '3.11'
2524
- '3.12'

.github/workflows/release.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ jobs:
5555
fail-fast: false
5656
matrix:
5757
python-version:
58-
- '3.9'
5958
- '3.10'
6059
- '3.11'
6160
- '3.12'

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ This project is maintained by [The Movement Cooperative](https://movementcoopera
1616
after [Lucy Parsons](https://en.wikipedia.org/wiki/Lucy_Parsons). The Movement Cooperative is a member-led organization
1717
focused on providing data, tools, and strategic support for the progressive community.
1818

19-
Parsons is only supported for Python 3.9-13.
19+
Parsons is only supported for Python 3.10-13.
2020

2121
## Table of Contents
2222

parsons/action_network/action_network.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import logging
33
import re
44
import warnings
5-
from typing import Literal, Union
5+
from typing import Literal
66

77
from parsons import Table
88
from parsons.utilities import check_env
@@ -1154,7 +1154,7 @@ def get_person(self, person_id):
11541154

11551155
def upsert_person(
11561156
self,
1157-
email_address: Union[str, list[str], list[dict[str, str]]] = None,
1157+
email_address: str | list[str] | list[dict[str, str]] = None,
11581158
given_name=None,
11591159
family_name=None,
11601160
tags=None,

parsons/catalist/catalist.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import time
1010
import urllib
1111
from pathlib import Path
12-
from typing import Optional, Union
1312
from zipfile import ZipFile
1413

1514
from parsons.etl import Table
@@ -64,7 +63,7 @@ def __init__(
6463
client_secret: str,
6564
sftp_username: str,
6665
sftp_password: str,
67-
client_audience: Optional[str] = None,
66+
client_audience: str | None = None,
6867
) -> None:
6968
self.client_id = client_id
7069
self.client_secret = client_secret
@@ -78,7 +77,7 @@ def __init__(
7877
)
7978
self.sftp = SFTP("t.catalist.us", sftp_username, sftp_password, timeout=7200)
8079

81-
def load_table_to_sftp(self, table: Table, input_subfolder: Optional[str] = None) -> str:
80+
def load_table_to_sftp(self, table: Table, input_subfolder: str | None = None) -> str:
8281
"""Load table to Catalist sftp bucket as gzipped CSV for matching.
8382
8483
If input_subfolder is specific, the file will be uploaded to a subfolder of the
@@ -114,11 +113,11 @@ def match(
114113
self,
115114
table: Table,
116115
export: bool = False,
117-
description: Optional[str] = None,
118-
export_filename_suffix: Optional[str] = None,
119-
input_subfolder: Optional[str] = None,
116+
description: str | None = None,
117+
export_filename_suffix: str | None = None,
118+
input_subfolder: str | None = None,
120119
copy_to_sandbox: bool = False,
121-
static_values: Optional[dict[str, Union[str, int]]] = None,
120+
static_values: dict[str, str | int] | None = None,
122121
wait: int = 30,
123122
) -> Table:
124123
"""Load table to the Catalist Match API, returns matched table.
@@ -165,11 +164,11 @@ def upload(
165164
table: Table,
166165
template_id: str = "48827",
167166
export: bool = False,
168-
description: Optional[str] = None,
169-
export_filename_suffix: Optional[str] = None,
170-
input_subfolder: Optional[str] = None,
167+
description: str | None = None,
168+
export_filename_suffix: str | None = None,
169+
input_subfolder: str | None = None,
171170
copy_to_sandbox: bool = False,
172-
static_values: Optional[dict[str, Union[str, int]]] = None,
171+
static_values: dict[str, str | int] | None = None,
173172
) -> dict:
174173
"""Load table to the Catalist Match API, returns response with job metadata.
175174
@@ -222,7 +221,7 @@ def upload(
222221
endpoint = "/".join(endpoint_params)
223222

224223
# Assemble query parameters
225-
query_params: dict[str, Union[str, int]] = {"token": self.connection.token["access_token"]}
224+
query_params: dict[str, str | int] = {"token": self.connection.token["access_token"]}
226225
if copy_to_sandbox:
227226
query_params["copyToSandbox"] = "true"
228227
if static_values:
@@ -242,10 +241,10 @@ def upload(
242241

243242
def action(
244243
self,
245-
file_ids: Union[str, list[str]],
244+
file_ids: str | list[str],
246245
match: bool = False,
247246
export: bool = False,
248-
export_filename_suffix: Optional[str] = None,
247+
export_filename_suffix: str | None = None,
249248
copy_to_sandbox: bool = False,
250249
) -> list[dict]:
251250
"""Perform actions on existing files.

parsons/databases/database_connector.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from abc import ABC, abstractmethod
2-
from typing import Optional, Union
32

43
from parsons.etl.table import Table
54

@@ -152,7 +151,7 @@ def copy(self, tbl: Table, table_name: str, if_exists: str):
152151
pass
153152

154153
@abstractmethod
155-
def query(self, sql: str, parameters: Optional[Union[list, dict]] = None) -> Optional[Table]:
154+
def query(self, sql: str, parameters: list | dict | None = None) -> Table | None:
156155
"""Execute a query against the database. Will return ``None`` if the query returns empty.
157156
158157
To include python variables in your query, it is recommended to pass them as parameters,

parsons/databases/discover_database.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import os
2-
from typing import Optional, Union
32

43
from parsons.databases.database_connector import DatabaseConnector
54
from parsons.databases.mysql import MySQL
@@ -9,9 +8,7 @@
98

109

1110
def discover_database(
12-
default_connector: Optional[
13-
Union[type[DatabaseConnector], list[type[DatabaseConnector]]]
14-
] = None,
11+
default_connector: type[DatabaseConnector] | list[type[DatabaseConnector]] | None = None,
1512
) -> DatabaseConnector:
1613
"""Create an appropriate ``DatabaseConnector`` based on environmental variables.
1714

parsons/databases/postgres/postgres.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import logging
22
import os
33
from pathlib import Path
4-
from typing import Optional
54

65
from parsons.databases.alchemy import Alchemy
76
from parsons.databases.database_connector import DatabaseConnector
@@ -120,7 +119,7 @@ def get_updated_rows(
120119
updated_at_column: str,
121120
cutoff_value,
122121
offset: int = 0,
123-
chunk_size: Optional[int] = None,
122+
chunk_size: int | None = None,
124123
) -> Table:
125124
"""Get rows that have a greater updated_at_column value than the one provided."""
126125
sql = f"""

parsons/databases/postgres/postgres_core.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import pickle
33
from contextlib import contextmanager
44
from pathlib import Path
5-
from typing import Optional
65

76
import petl
87
import psycopg2
@@ -65,7 +64,7 @@ def cursor(self, connection):
6564
finally:
6665
cur.close()
6766

68-
def query(self, sql: str, parameters: Optional[list] = None) -> Optional[Table]:
67+
def query(self, sql: str, parameters: list | None = None) -> Table | None:
6968
"""
7069
Execute a query against the database. Will return ``None`` if the query returns zero rows.
7170

parsons/databases/redshift/redshift.py

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import random
77
from contextlib import contextmanager
88
from pathlib import Path
9-
from typing import Optional
109

1110
import petl
1211
import psycopg2
@@ -156,7 +155,7 @@ def cursor(self, connection):
156155
finally:
157156
cur.close()
158157

159-
def query(self, sql: str, parameters: Optional[list] = None) -> Optional[Table]:
158+
def query(self, sql: str, parameters: list | None = None) -> Table | None:
160159
"""
161160
Execute a query against the Redshift database. Will return ``None``
162161
if the query returns zero rows.
@@ -474,30 +473,30 @@ def copy(
474473
table_name: str,
475474
if_exists: str = "fail",
476475
max_errors: int = 0,
477-
distkey: Optional[str] = None,
478-
sortkey: Optional[str] = None,
479-
padding: Optional[float] = None,
480-
statupdate: Optional[bool] = None,
481-
compupdate: Optional[bool] = None,
476+
distkey: str | None = None,
477+
sortkey: str | None = None,
478+
padding: float | None = None,
479+
statupdate: bool | None = None,
480+
compupdate: bool | None = None,
482481
acceptanydate: bool = True,
483482
emptyasnull: bool = True,
484483
blanksasnull: bool = True,
485-
nullas: Optional[str] = None,
484+
nullas: str | None = None,
486485
acceptinvchars: bool = True,
487486
dateformat: str = "auto",
488487
timeformat: str = "auto",
489-
varchar_max: Optional[list[str]] = None,
488+
varchar_max: list[str] | None = None,
490489
truncatecolumns: bool = False,
491-
columntypes: Optional[dict] = None,
492-
specifycols: Optional[bool] = None,
490+
columntypes: dict | None = None,
491+
specifycols: bool | None = None,
493492
alter_table: bool = False,
494493
alter_table_cascade: bool = False,
495-
aws_access_key_id: Optional[str] = None,
496-
aws_secret_access_key: Optional[str] = None,
497-
iam_role: Optional[str] = None, # Unused - Should we remove?
494+
aws_access_key_id: str | None = None,
495+
aws_secret_access_key: str | None = None,
496+
iam_role: str | None = None, # Unused - Should we remove?
498497
cleanup_s3_file: bool = True,
499-
template_table: Optional[str] = None,
500-
temp_bucket_region: Optional[str] = None,
498+
template_table: str | None = None,
499+
temp_bucket_region: str | None = None,
501500
strict_length: bool = True,
502501
csv_encoding: str = "utf-8",
503502
):

0 commit comments

Comments
 (0)