diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 67d188e..2470bf5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] os: [ubuntu-latest, macOS-latest, windows-latest] steps: diff --git a/README.md b/README.md index d0a95e7..e0b5168 100644 --- a/README.md +++ b/README.md @@ -321,7 +321,7 @@ Estimated cost: $0.01 Click to unfold installation -pypinfo is distributed on **PyPI** as a universal wheel and is available on Linux/macOS and Windows and supports Python 3.7+. +pypinfo is distributed on **PyPI** as a universal wheel and is available on Linux, macOS and Windows. This is relatively painless, I swear. diff --git a/pypinfo/cli.py b/pypinfo/cli.py index 52b0f79..271e434 100644 --- a/pypinfo/cli.py +++ b/pypinfo/cli.py @@ -1,5 +1,4 @@ from decimal import ROUND_UP, Decimal -from typing import List import click from binary import TEBIBYTE, convert_units @@ -102,7 +101,7 @@ def pypinfo( ctx: click.Context, project: str, - fields: List[str], + fields: list[str], auth: str, run: bool, json: bool, diff --git a/pypinfo/core.py b/pypinfo/core.py index c29c17d..3b44e05 100644 --- a/pypinfo/core.py +++ b/pypinfo/core.py @@ -2,7 +2,8 @@ import json import os from datetime import date, datetime -from typing import Any, Dict, Iterable, List, Optional, Tuple +from typing import Any, Optional +from collections.abc import Iterable from google.cloud.bigquery import Client from google.cloud.bigquery.job import QueryJobConfig @@ -22,7 +23,7 @@ END_DATE = '-1' DEFAULT_LIMIT = 10 -Rows = List[List[str]] +Rows = list[list[str]] def create_config() -> QueryJobConfig: @@ -31,7 +32,7 @@ def create_config() -> QueryJobConfig: return config -def normalize_dates(start_date: str, end_date: str) -> Tuple[str, str]: +def normalize_dates(start_date: str, end_date: str) -> tuple[str, str]: """If a date is yyyy-mm, normalize as first or last yyyy-mm-dd of the month. Otherwise, return unchanged. """ @@ -85,7 +86,7 @@ def format_date(date: str, timestamp_format: str) -> str: return date -def month_ends(yyyy_mm: str) -> Tuple[str, str]: +def month_ends(yyyy_mm: str) -> tuple[str, str]: """Helper to return start_date and end_date of a month as yyyy-mm-dd""" year, month = map(int, yyyy_mm.split("-")) first = date(year, month, 1) @@ -94,7 +95,7 @@ def month_ends(yyyy_mm: str) -> Tuple[str, str]: return str(first), str(last) -def strip_trailing_zero(release: Tuple[int, ...]) -> Tuple[int, ...]: +def strip_trailing_zero(release: tuple[int, ...]) -> tuple[int, ...]: """Helper to strip trailing 0 in a tuple of integers""" new_len = len(release) while new_len > 1 and release[new_len - 1] == 0: @@ -271,7 +272,7 @@ def add_percentages(rows: Rows, include_sign: bool = True) -> Rows: return rows -def get_download_total(rows: Rows) -> Tuple[int, int]: +def get_download_total(rows: Rows) -> tuple[int, int]: """Return the total downloads, and the downloads column""" headers = rows.pop(0) index = headers.index('download_count') @@ -341,13 +342,13 @@ def tabulate(rows: Rows, markdown: bool = False) -> str: return tabulated -def format_json(rows: Rows, query_info: Dict[str, Any], indent: Optional[int]) -> str: +def format_json(rows: Rows, query_info: dict[str, Any], indent: Optional[int]) -> str: headers, *_data = rows - data: List[Any] = _data - items: List[Dict[str, Any]] = [] + data: list[Any] = _data + items: list[dict[str, Any]] = [] for d in data: - item: Dict[str, Any] = {} + item: dict[str, Any] = {} for i in range(len(headers)): if d[i].isdigit(): d[i] = int(d[i]) diff --git a/pypinfo/db.py b/pypinfo/db.py index 7012978..6967611 100644 --- a/pypinfo/db.py +++ b/pypinfo/db.py @@ -1,6 +1,7 @@ import contextlib import os -from typing import Iterator, Optional +from typing import Optional +from collections.abc import Iterator from platformdirs import user_data_dir from tinydb import TinyDB, Query, where diff --git a/pyproject.toml b/pyproject.toml index c6b512c..f982752 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ name = "pypinfo" description = "View PyPI download statistics with ease." readme = "README.md" license = "MIT" -requires-python = ">=3.8" +requires-python = ">=3.9" keywords = [ "bigquery", "downloads", @@ -27,7 +27,6 @@ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", diff --git a/tests/test_core.py b/tests/test_core.py index 09ee057..4e2661e 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1,5 +1,6 @@ from freezegun import freeze_time -from typing import Any, Iterator, List, Tuple +from typing import Any +from collections.abc import Iterator import copy import pytest import re @@ -172,7 +173,7 @@ def test_build_query() -> None: def test_build_query_specifier() -> None: # pypinfo -sd -2 -ed -1 -l 20 --test 'foo==1' project = "foo==1" - all_fields: List[Field] = [] + all_fields: list[Field] = [] start_date = "-2" end_date = "-1" days = None @@ -273,7 +274,7 @@ def test_build_query_where() -> None: def test_build_query_no_project() -> None: # pypinfo -sd -2 -ed -1 -l 20 --all --test '' project = "" - all_fields: List[Field] = [] + all_fields: list[Field] = [] start_date = "-2" end_date = "-1" days = None @@ -508,7 +509,7 @@ def test_format_json() -> None: def test_parse_query_result() -> None: - data: List[Tuple[Any, ...]] = [ + data: list[tuple[Any, ...]] = [ ("name", "other"), ("name1", 1), ("name2", 2), @@ -523,7 +524,7 @@ class MockRowIterator(RowIterator): # type: ignore[misc] def __init__(self) -> None: super().__init__(None, None, None, schema) - def __iter__(self) -> Iterator[Tuple[Any, ...]]: + def __iter__(self) -> Iterator[tuple[Any, ...]]: return iter(data[1:]) actual = core.parse_query_result(MockRowIterator()) diff --git a/tox.ini b/tox.ini index 6efe2f7..ca99a51 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,6 @@ [tox] minversion = 1.9 envlist = - py38, py39, py310, py311,