Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/python-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ jobs:
fail-fast: false
matrix:
python-version:
- '3.9'
- '3.10'
- '3.11'
- '3.12'
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ jobs:
fail-fast: false
matrix:
python-version:
- '3.9'
- '3.10'
- '3.11'
- '3.12'
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.13.0
hooks:
- id: ruff
- id: ruff-check
- id: ruff-format
- repo: https://github.com/PyCQA/bandit
rev: 1.8.6
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This project is maintained by [The Movement Cooperative](https://movementcoopera
after [Lucy Parsons](https://en.wikipedia.org/wiki/Lucy_Parsons). The Movement Cooperative is a member-led organization
focused on providing data, tools, and strategic support for the progressive community.

Parsons is only supported for Python 3.9-13.
Parsons is only supported for Python 3.10-13.

## Table of Contents

Expand Down
4 changes: 2 additions & 2 deletions parsons/action_network/action_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import logging
import re
import warnings
from typing import Literal, Union
from typing import Literal

from parsons import Table
from parsons.utilities import check_env
Expand Down Expand Up @@ -1154,7 +1154,7 @@ def get_person(self, person_id):

def upsert_person(
self,
email_address: Union[str, list[str], list[dict[str, str]]] = None,
email_address: str | list[str] | list[dict[str, str]] = None,
given_name=None,
family_name=None,
tags=None,
Expand Down
27 changes: 13 additions & 14 deletions parsons/catalist/catalist.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import time
import urllib
from pathlib import Path
from typing import Optional, Union
from zipfile import ZipFile

from parsons.etl import Table
Expand Down Expand Up @@ -64,7 +63,7 @@ def __init__(
client_secret: str,
sftp_username: str,
sftp_password: str,
client_audience: Optional[str] = None,
client_audience: str | None = None,
) -> None:
self.client_id = client_id
self.client_secret = client_secret
Expand All @@ -78,7 +77,7 @@ def __init__(
)
self.sftp = SFTP("t.catalist.us", sftp_username, sftp_password, timeout=7200)

def load_table_to_sftp(self, table: Table, input_subfolder: Optional[str] = None) -> str:
def load_table_to_sftp(self, table: Table, input_subfolder: str | None = None) -> str:
"""Load table to Catalist sftp bucket as gzipped CSV for matching.

If input_subfolder is specific, the file will be uploaded to a subfolder of the
Expand Down Expand Up @@ -114,11 +113,11 @@ def match(
self,
table: Table,
export: bool = False,
description: Optional[str] = None,
export_filename_suffix: Optional[str] = None,
input_subfolder: Optional[str] = None,
description: str | None = None,
export_filename_suffix: str | None = None,
input_subfolder: str | None = None,
copy_to_sandbox: bool = False,
static_values: Optional[dict[str, Union[str, int]]] = None,
static_values: dict[str, str | int] | None = None,
wait: int = 30,
) -> Table:
"""Load table to the Catalist Match API, returns matched table.
Expand Down Expand Up @@ -165,11 +164,11 @@ def upload(
table: Table,
template_id: str = "48827",
export: bool = False,
description: Optional[str] = None,
export_filename_suffix: Optional[str] = None,
input_subfolder: Optional[str] = None,
description: str | None = None,
export_filename_suffix: str | None = None,
input_subfolder: str | None = None,
copy_to_sandbox: bool = False,
static_values: Optional[dict[str, Union[str, int]]] = None,
static_values: dict[str, str | int] | None = None,
) -> dict:
"""Load table to the Catalist Match API, returns response with job metadata.

Expand Down Expand Up @@ -222,7 +221,7 @@ def upload(
endpoint = "/".join(endpoint_params)

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

def action(
self,
file_ids: Union[str, list[str]],
file_ids: str | list[str],
match: bool = False,
export: bool = False,
export_filename_suffix: Optional[str] = None,
export_filename_suffix: str | None = None,
copy_to_sandbox: bool = False,
) -> list[dict]:
"""Perform actions on existing files.
Expand Down
3 changes: 1 addition & 2 deletions parsons/databases/database_connector.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from abc import ABC, abstractmethod
from typing import Optional, Union

from parsons.etl.table import Table

Expand Down Expand Up @@ -152,7 +151,7 @@ def copy(self, tbl: Table, table_name: str, if_exists: str):
pass

@abstractmethod
def query(self, sql: str, parameters: Optional[Union[list, dict]] = None) -> Optional[Table]:
def query(self, sql: str, parameters: list | dict | None = None) -> Table | None:
"""Execute a query against the database. Will return ``None`` if the query returns empty.

To include python variables in your query, it is recommended to pass them as parameters,
Expand Down
5 changes: 1 addition & 4 deletions parsons/databases/discover_database.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import os
from typing import Optional, Union

from parsons.databases.database_connector import DatabaseConnector
from parsons.databases.mysql import MySQL
Expand All @@ -9,9 +8,7 @@


def discover_database(
default_connector: Optional[
Union[type[DatabaseConnector], list[type[DatabaseConnector]]]
] = None,
default_connector: type[DatabaseConnector] | list[type[DatabaseConnector]] | None = None,
) -> DatabaseConnector:
"""Create an appropriate ``DatabaseConnector`` based on environmental variables.

Expand Down
3 changes: 1 addition & 2 deletions parsons/databases/postgres/postgres.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import logging
import os
from pathlib import Path
from typing import Optional

from parsons.databases.alchemy import Alchemy
from parsons.databases.database_connector import DatabaseConnector
Expand Down Expand Up @@ -120,7 +119,7 @@ def get_updated_rows(
updated_at_column: str,
cutoff_value,
offset: int = 0,
chunk_size: Optional[int] = None,
chunk_size: int | None = None,
) -> Table:
"""Get rows that have a greater updated_at_column value than the one provided."""
sql = f"""
Expand Down
3 changes: 1 addition & 2 deletions parsons/databases/postgres/postgres_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import pickle
from contextlib import contextmanager
from pathlib import Path
from typing import Optional

import petl
import psycopg2
Expand Down Expand Up @@ -65,7 +64,7 @@ def cursor(self, connection):
finally:
cur.close()

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

Expand Down
31 changes: 15 additions & 16 deletions parsons/databases/redshift/redshift.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import random
from contextlib import contextmanager
from pathlib import Path
from typing import Optional

import petl
import psycopg2
Expand Down Expand Up @@ -156,7 +155,7 @@ def cursor(self, connection):
finally:
cur.close()

def query(self, sql: str, parameters: Optional[list] = None) -> Optional[Table]:
def query(self, sql: str, parameters: list | None = None) -> Table | None:
"""
Execute a query against the Redshift database. Will return ``None``
if the query returns zero rows.
Expand Down Expand Up @@ -474,30 +473,30 @@ def copy(
table_name: str,
if_exists: str = "fail",
max_errors: int = 0,
distkey: Optional[str] = None,
sortkey: Optional[str] = None,
padding: Optional[float] = None,
statupdate: Optional[bool] = None,
compupdate: Optional[bool] = None,
distkey: str | None = None,
sortkey: str | None = None,
padding: float | None = None,
statupdate: bool | None = None,
compupdate: bool | None = None,
acceptanydate: bool = True,
emptyasnull: bool = True,
blanksasnull: bool = True,
nullas: Optional[str] = None,
nullas: str | None = None,
acceptinvchars: bool = True,
dateformat: str = "auto",
timeformat: str = "auto",
varchar_max: Optional[list[str]] = None,
varchar_max: list[str] | None = None,
truncatecolumns: bool = False,
columntypes: Optional[dict] = None,
specifycols: Optional[bool] = None,
columntypes: dict | None = None,
specifycols: bool | None = None,
alter_table: bool = False,
alter_table_cascade: bool = False,
aws_access_key_id: Optional[str] = None,
aws_secret_access_key: Optional[str] = None,
iam_role: Optional[str] = None, # Unused - Should we remove?
aws_access_key_id: str | None = None,
aws_secret_access_key: str | None = None,
iam_role: str | None = None, # Unused - Should we remove?
cleanup_s3_file: bool = True,
template_table: Optional[str] = None,
temp_bucket_region: Optional[str] = None,
template_table: str | None = None,
temp_bucket_region: str | None = None,
strict_length: bool = True,
csv_encoding: str = "utf-8",
):
Expand Down
6 changes: 3 additions & 3 deletions parsons/databases/sqlite/sqlite.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from collections.abc import Iterator
from contextlib import contextmanager
from pathlib import Path
from typing import Literal, Optional, Union
from typing import Literal

import petl

Expand Down Expand Up @@ -61,15 +61,15 @@ def cursor(self, connection) -> Iterator[sqlite3.Cursor]:
finally:
cur.close()

def query(self, sql: str, parameters: Optional[Union[list, dict]] = None) -> Optional[Table]:
def query(self, sql: str, parameters: list | dict | None = None) -> Table | None:
with self.connection() as connection:
return self.query_with_connection(sql, connection, parameters=parameters)

def query_with_connection(
self,
sql: str,
connection: sqlite3.Connection,
parameters: Optional[Union[list, dict]] = None,
parameters: list | dict | None = None,
commit: bool = True,
return_values: bool = True,
):
Expand Down
3 changes: 1 addition & 2 deletions parsons/etl/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import pickle
from enum import Enum
from pathlib import Path
from typing import Union

import petl

Expand Down Expand Up @@ -47,7 +46,7 @@ class Table(ETL, ToFrom):

def __init__(
self,
lst: Union[list, tuple, petl.util.base.Table, _EmptyDefault] = _EMPTYDEFAULT,
lst: list | tuple | petl.util.base.Table | _EmptyDefault = _EMPTYDEFAULT,
):
self.table = None

Expand Down
5 changes: 2 additions & 3 deletions parsons/etl/tofrom.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import io
import json
from pathlib import Path
from typing import Optional

import petl

Expand Down Expand Up @@ -617,8 +616,8 @@ def to_postgres(
def to_bigquery(
self,
table_name: str,
app_creds: Optional[str] = None,
project: Optional[str] = None,
app_creds: str | None = None,
project: str | None = None,
**kwargs,
):
"""
Expand Down
5 changes: 2 additions & 3 deletions parsons/formstack/formstack.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import logging
from typing import Optional

from parsons import Table
from parsons.utilities import check_env
Expand All @@ -20,7 +19,7 @@ class Formstack:
``FORMSTACK_API_TOKEN`` env variable is set.
"""

def __init__(self, api_token: Optional[str] = None):
def __init__(self, api_token: str | None = None):
self.api_token = check_env.check("FORMSTACK_API_TOKEN", api_token)
headers = {
"Accept": "application/json",
Expand Down Expand Up @@ -116,7 +115,7 @@ def get_folders(self) -> Table:
tbl.remove_column("subfolders")
return tbl

def get_forms(self, form_name: Optional[str] = None, folder_id: Optional[int] = None) -> Table:
def get_forms(self, form_name: str | None = None, folder_id: int | None = None) -> Table:
"""
Get all forms on your account.

Expand Down
Loading
Loading