Skip to content

Commit

Permalink
Merge branch 'main' into custom-short-url
Browse files Browse the repository at this point in the history
  • Loading branch information
vidya-ram committed Sep 14, 2023
2 parents 061cd28 + 81cce97 commit 6a3110d
Show file tree
Hide file tree
Showing 264 changed files with 1,990 additions and 2,164 deletions.
17 changes: 8 additions & 9 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,13 @@ repos:
'PYSEC-2023-101', # https://github.com/pytest-dev/pytest-selenium/issues/310
]
files: ^requirements/.*\.txt$
- repo: https://github.com/asottile/pyupgrade
rev: v3.10.1
hooks:
- id: pyupgrade
args: ['--keep-runtime-typing', '--py310-plus']
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.286
rev: v0.0.287
hooks:
- id: ruff
args: ['--fix', '--exit-non-zero-on-fix']
Expand All @@ -64,12 +69,6 @@ repos:
'--remove-unused-variables',
'--remove-duplicate-keys',
]
- repo: https://github.com/asottile/pyupgrade
rev: v3.10.1
hooks:
- id: pyupgrade
args:
['--keep-runtime-typing', '--py3-plus', '--py36-plus', '--py37-plus']
- repo: https://github.com/asottile/yesqa
rev: v1.5.0
hooks:
Expand Down Expand Up @@ -99,7 +98,7 @@ repos:
additional_dependencies:
- tomli
- repo: https://github.com/psf/black
rev: 23.7.0
rev: 23.9.1
hooks:
- id: black
# Mypy is temporarily disabled until the SQLAlchemy 2.0 migration is complete
Expand Down Expand Up @@ -189,7 +188,7 @@ repos:
- id: forbid-tabs
- id: remove-tabs
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.0.2
rev: v3.0.3
hooks:
- id: prettier
args:
Expand Down
11 changes: 11 additions & 0 deletions funnel/assets/sass/base/_utils.scss
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,17 @@
width: 100%;
}

.img-rounded-border {
border-radius: 16px;
}

.img-fit {
position: absolute;
object-fit: fill;
width: 100%;
height: 100%;
}

// ============================================================================
// Overlay
// ============================================================================
Expand Down
4 changes: 4 additions & 0 deletions funnel/assets/sass/components/_card.scss
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@

.card--shaped {
border-radius: 16px 16px 0 16px;
.card__image-wrapper {
border-radius: 16px 16px 0 0;
overflow: hidden;
}
}

.clickable-card:focus,
Expand Down
2 changes: 1 addition & 1 deletion funnel/assets/sass/components/_ticket-modal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
}

.price-btn {
min-width: 150px;
min-width: 200px;
font-size: inherit;
padding: 0;
display: flex;
Expand Down
3 changes: 1 addition & 2 deletions funnel/cli/geodata.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from dataclasses import dataclass
from datetime import datetime
from decimal import Decimal
from typing import Optional
from urllib.parse import urljoin

import click
Expand Down Expand Up @@ -110,7 +109,7 @@ class GeoAltNameRecord:
is_historic: str


def downloadfile(basepath: str, filename: str, folder: Optional[str] = None) -> None:
def downloadfile(basepath: str, filename: str, folder: str | None = None) -> None:
"""Download a geoname record file."""
if not folder:
folder_file = filename
Expand Down
4 changes: 2 additions & 2 deletions funnel/cli/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

from pathlib import Path
from typing import Any, Dict
from typing import Any

import click
from dotenv import dotenv_values
Expand All @@ -15,7 +15,7 @@


@app.shell_context_processor
def shell_context() -> Dict[str, Any]:
def shell_context() -> dict[str, Any]:
"""Insert variables into flask shell locals."""
return {'db': db, 'models': models}

Expand Down
19 changes: 9 additions & 10 deletions funnel/cli/periodic/mnrl.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
"""

import asyncio
from typing import List, Set, Tuple

import click
import httpx
Expand Down Expand Up @@ -84,13 +83,13 @@ async def read(self, size: int) -> bytes:
return b''


async def get_existing_phone_numbers(prefix: str) -> Set[str]:
async def get_existing_phone_numbers(prefix: str) -> set[str]:
"""Async wrapper for PhoneNumber.get_numbers."""
# TODO: This is actually an async-blocking call. We need full stack async here.
return PhoneNumber.get_numbers(prefix=prefix, remove=True)


async def get_mnrl_json_file_list(apikey: str) -> List[str]:
async def get_mnrl_json_file_list(apikey: str) -> list[str]:
"""
Return filenames for the currently published MNRL JSON files.
Expand All @@ -117,7 +116,7 @@ async def get_mnrl_json_file_list(apikey: str) -> List[str]:

async def get_mnrl_json_file_numbers(
client: httpx.AsyncClient, apikey: str, filename: str
) -> Tuple[str, Set[str]]:
) -> tuple[str, set[str]]:
"""Return phone numbers from an MNRL JSON file URL."""
async with client.stream(
'GET',
Expand All @@ -136,7 +135,7 @@ async def get_mnrl_json_file_numbers(
}


async def forget_phone_numbers(phone_numbers: Set[str], prefix: str) -> None:
async def forget_phone_numbers(phone_numbers: set[str], prefix: str) -> None:
"""Mark phone numbers as forgotten."""
for unprefixed in phone_numbers:
number = prefix + unprefixed
Expand Down Expand Up @@ -166,20 +165,20 @@ async def forget_phone_numbers(phone_numbers: Set[str], prefix: str) -> None:

async def process_mnrl_files(
apikey: str,
existing_phone_numbers: Set[str],
existing_phone_numbers: set[str],
phone_prefix: str,
mnrl_filenames: List[str],
) -> Tuple[Set[str], int, int]:
mnrl_filenames: list[str],
) -> tuple[set[str], int, int]:
"""
Scan all MNRL files and return a tuple of results.
:return: Tuple of number to be revoked (set), total expired numbers in the MNRL,
and count of failures when accessing the MNRL lists
"""
revoked_phone_numbers: Set[str] = set()
revoked_phone_numbers: set[str] = set()
mnrl_total_count = 0
failures = 0
async_tasks: Set[asyncio.Task] = set()
async_tasks: set[asyncio.Task] = set()
with Progress(transient=True) as progress:
ptask = progress.add_task(
f"Processing {len(mnrl_filenames)} MNRL files", total=len(mnrl_filenames)
Expand Down
24 changes: 12 additions & 12 deletions funnel/cli/periodic/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
from __future__ import annotations

import asyncio
from collections.abc import Sequence
from dataclasses import dataclass
from datetime import datetime
from typing import Dict, Optional, Sequence, Union, cast, overload
from typing_extensions import Literal
from typing import Literal, cast, overload
from urllib.parse import unquote

import click
Expand Down Expand Up @@ -80,10 +80,10 @@ class MatomoResponse(DataClassJsonMixin):
nb_visits: int = 0
nb_uniq_visitors: int = 0
nb_users: int = 0
url: Optional[str] = None
url: str | None = None
segment: str = ''

def get_url(self) -> Optional[str]:
def get_url(self) -> str | None:
url = self.url
if url:
# If URL is a path (/path) or schemeless (//host/path), return as is
Expand All @@ -109,9 +109,9 @@ class MatomoData:
referrers: Sequence[MatomoResponse]
socials: Sequence[MatomoResponse]
pages: Sequence[MatomoResponse]
visits_day: Optional[MatomoResponse] = None
visits_week: Optional[MatomoResponse] = None
visits_month: Optional[MatomoResponse] = None
visits_day: MatomoResponse | None = None
visits_week: MatomoResponse | None = None
visits_month: MatomoResponse | None = None


# --- Matomo analytics -----------------------------------------------------------------
Expand All @@ -127,13 +127,13 @@ async def matomo_response_json(
@overload
async def matomo_response_json(
client: httpx.AsyncClient, url: str, sequence: Literal[False]
) -> Optional[MatomoResponse]:
) -> MatomoResponse | None:
...


async def matomo_response_json(
client: httpx.AsyncClient, url: str, sequence: bool = True
) -> Union[Optional[MatomoResponse], Sequence[MatomoResponse]]:
) -> MatomoResponse | Sequence[MatomoResponse] | None:
"""Process Matomo's JSON response."""
try:
response = await client.get(url, timeout=30)
Expand Down Expand Up @@ -247,7 +247,7 @@ async def matomo_stats() -> MatomoData:
# --- Internal database analytics ------------------------------------------------------


def data_sources() -> Dict[str, DataSource]:
def data_sources() -> dict[str, DataSource]:
"""Return sources for daily stats report."""
return {
# `login_sessions`, `app_login_sessions` and `returning_users` (added below) are
Expand Down Expand Up @@ -281,7 +281,7 @@ def data_sources() -> Dict[str, DataSource]:
}


async def user_stats() -> Dict[str, ResourceStats]:
async def user_stats() -> dict[str, ResourceStats]:
"""Retrieve user statistics from internal database."""
# Dates in report timezone (for display)
tz = pytz.timezone(app.config['TIMEZONE'])
Expand All @@ -296,7 +296,7 @@ async def user_stats() -> Dict[str, ResourceStats]:
last_month = today - relativedelta(months=1)
two_months_ago = today - relativedelta(months=2)

stats: Dict[str, ResourceStats] = {
stats: dict[str, ResourceStats] = {
key: ResourceStats(
day=ds.basequery.filter(
ds.datecolumn >= yesterday, ds.datecolumn < today
Expand Down
17 changes: 9 additions & 8 deletions funnel/cli/refresh/markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

from __future__ import annotations

from typing import ClassVar, Dict, Generic, Iterable, List, Optional, Set, Type, TypeVar
from collections.abc import Iterable
from typing import ClassVar, Generic, TypeVar

import click
import rich.progress
Expand All @@ -17,27 +18,27 @@
class MarkdownModel(Generic[_M]):
"""Holding class for a model that has markdown fields with custom configuration."""

registry: ClassVar[Dict[str, MarkdownModel]] = {}
config_registry: ClassVar[Dict[str, Set[MarkdownModel]]] = {}
registry: ClassVar[dict[str, MarkdownModel]] = {}
config_registry: ClassVar[dict[str, set[MarkdownModel]]] = {}

def __init__(self, model: Type[_M], fields: Set[str]) -> None:
def __init__(self, model: type[_M], fields: set[str]) -> None:
self.name = model.__tablename__
self.model = model
self.fields = fields
self.config_fields: Dict[str, Set[str]] = {}
self.config_fields: dict[str, set[str]] = {}
for field in fields:
config = getattr(model, field).original_property.composite_class.config.name
self.config_fields.setdefault(config, set()).add(field)

@classmethod
def register(cls, model: Type[_M], fields: Set[str]) -> None:
def register(cls, model: type[_M], fields: set[str]) -> None:
"""Create an instance and add it to the registry."""
obj = cls(model, fields)
for config in obj.config_fields:
cls.config_registry.setdefault(config, set()).add(obj)
cls.registry[obj.name] = obj

def reparse(self, config: Optional[str] = None, obj: Optional[_M] = None) -> None:
def reparse(self, config: str | None = None, obj: _M | None = None) -> None:
"""Reparse Markdown fields, optionally for a single config profile."""
if config and config not in self.config_fields:
return
Expand Down Expand Up @@ -113,7 +114,7 @@ def reparse(self, config: Optional[str] = None, obj: Optional[_M] = None) -> Non
help="Reparse content at this URL",
)
def markdown(
content: List[str], config: Optional[str], allcontent: bool, url: Optional[str]
content: list[str], config: str | None, allcontent: bool, url: str | None
) -> None:
"""Reparse Markdown content."""
if allcontent:
Expand Down
Loading

0 comments on commit 6a3110d

Please sign in to comment.