Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: typer doesn't support union types from python 3.11 #220

Merged
merged 2 commits into from
May 2, 2023
Merged
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
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ repos:
entry: pyupgrade
language: system
types: [python]
args: [--py311-plus, --keep-runtime-typing]
args: [--py39-plus, --keep-runtime-typing]
- id: reorder-python-imports
name: Reorder python imports
entry: reorder-python-imports
Expand Down
9 changes: 5 additions & 4 deletions pgbelt/cmd/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from inspect import Parameter
from inspect import signature
from typing import Any
from typing import Optional # noqa: F401 # Needed until tiangolo/typer#522 is fixed)
from typing import TypeVar

from pgbelt.config import get_all_configs_async
Expand All @@ -19,10 +20,10 @@


def run_with_configs(
decorated_func: Callable[..., Awaitable[T | None]] = None,
decorated_func: Callable[..., Awaitable[Optional[T]]] = None,
skip_src: bool = False,
skip_dst: bool = False,
results_callback: Callable[[list[T]], Awaitable[Any | None]] | None = None,
results_callback: Optional[Callable[[list[T]], Awaitable[Optional[Any]]]] = None,
) -> Callable:
"""
Decorator for async commands. Implementations should take one Awaitable[DbupgradeConfig] arg
Expand Down Expand Up @@ -50,7 +51,7 @@ def decorator(func):

# The name, docstring, and signature of the implementation is preserved. Important for add_command
@wraps(func)
async def wrapper(dc: str, db: str | None, **kwargs):
async def wrapper(dc: str, db: Optional[str], **kwargs):
# If db is specified we only want to run on one of them
if db is not None:
results = [
Expand Down Expand Up @@ -100,7 +101,7 @@ def add_command(app: Typer, command: Callable):
if iscoroutinefunction(command):

@app.command(name=name)
def cmdwrapper(dc: str, db: str | None = Argument(None), **kwargs):
def cmdwrapper(dc: str, db: Optional[str] = Argument(None), **kwargs):
run(command(dc, db, **kwargs))

# Synchronous commands can only be run on one db at a time
Expand Down
9 changes: 5 additions & 4 deletions pgbelt/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from collections.abc import AsyncGenerator
from collections.abc import Awaitable
from os.path import join
from typing import Optional # noqa: F401 # Needed until tiangolo/typer#522 is fixed)

from pgbelt.config.models import DbupgradeConfig
from pgbelt.config.remote import resolve_remote_config
Expand All @@ -13,7 +14,7 @@

def get_config(
db: str, dc: str, skip_src: bool = False, skip_dst: bool = False
) -> DbupgradeConfig | None:
) -> Optional[DbupgradeConfig]:
"""
Get a configuration for one database pair synchronously.
"""
Expand All @@ -27,7 +28,7 @@ def get_config(

async def get_config_async(
db: str, dc: str, skip_src: bool = False, skip_dst: bool = False
) -> DbupgradeConfig | None:
) -> Optional[DbupgradeConfig]:
"""
Get configuration for one database pair asynchronously. Always prefers
locally cached configuration but attempts to resolve any uncached configuration
Expand Down Expand Up @@ -71,7 +72,7 @@ async def find_available_configs(confdir: str, dc: str) -> set[str]:
"""
result = set()
dc_dir = join(confdir, dc)
if not await (isdir(dc_dir)):
if not await isdir(dc_dir):
return set()
for db in await listdir(dc_dir):
if await isdir(join(dc_dir, db)) and await isfile(
Expand All @@ -83,7 +84,7 @@ async def find_available_configs(confdir: str, dc: str) -> set[str]:

async def get_all_configs_async(
dc: str, skip_src: bool = False, skip_dst: bool = False
) -> AsyncGenerator[Awaitable[DbupgradeConfig | None], None]:
) -> AsyncGenerator[Awaitable[Optional[DbupgradeConfig]], None]:
"""
A generator that produces Awaitables that resolve to DbupgradeConfigs or None

Expand Down
17 changes: 9 additions & 8 deletions pgbelt/config/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

from os.path import join
from typing import Optional # noqa: F401 # Needed until tiangolo/typer#522 is fixed)

from aiofiles import open as aopen
from aiofiles.os import remove
Expand All @@ -19,7 +20,7 @@ def config_file(db: str, dc: str) -> str:
return join(config_dir(db, dc), "config.json")


def not_empty(v) -> str | None:
def not_empty(v) -> Optional[str]:
if v == "":
raise ValueError
return v
Expand All @@ -34,7 +35,7 @@ class User(BaseModel):
"""

name: str
pw: str | None = None
pw: Optional[str] = None

_not_empty = validator("name", "pw", allow_reuse=True)(not_empty)

Expand All @@ -61,7 +62,7 @@ class DbConfig(BaseModel):
root_user: User
owner_user: User
pglogical_user: User
other_users: list[User] | None = None
other_users: Optional[list[User]] = None

_not_empty = validator("host", "ip", "db", "port", allow_reuse=True)(not_empty)

Expand Down Expand Up @@ -108,10 +109,10 @@ class DbupgradeConfig(BaseModel):

db: str
dc: str
src: DbConfig | None = None
dst: DbConfig | None = None
tables: list[str] | None = None
sequences: list[str] | None = None
src: Optional[DbConfig] = None
dst: Optional[DbConfig] = None
tables: Optional[list[str]] = None
sequences: Optional[list[str]] = None

_not_empty = validator("db", "dc", allow_reuse=True)(not_empty)

Expand Down Expand Up @@ -146,7 +147,7 @@ async def save(self):
logger.info("Cached config to disk.")

@classmethod
async def load(cls, db: str, dc: str) -> DbupgradeConfig | None:
async def load(cls, db: str, dc: str) -> Optional[DbupgradeConfig]:
"""
Load the specified configuration from disk if present.
If the existing config is invalid or does not exist return None.
Expand Down
7 changes: 4 additions & 3 deletions pgbelt/config/remote.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from importlib import import_module
from json import JSONDecodeError
from logging import Logger
from typing import Optional # noqa: F401 # Needed until tiangolo/typer#522 is fixed)

from aiofiles import open as aopen
from pgbelt.config.models import DbupgradeConfig
Expand Down Expand Up @@ -59,7 +60,7 @@ class Config:
arbitrary_types_allowed = True
extra = "ignore"

async def resolve(self) -> DbupgradeConfig | None:
async def resolve(self) -> Optional[DbupgradeConfig]:
"""
Called to retrieve the configuration from wherever your resolver gets it.
Return configuration as a DbupgradeConfig.
Expand All @@ -72,7 +73,7 @@ async def resolve(self) -> DbupgradeConfig | None:

async def load_remote_conf_def(
config_file: str, logger: Logger
) -> RemoteConfigDefinition | None:
) -> Optional[RemoteConfigDefinition]:
try:
logger.debug(f"Reading remote config definition from file {config_file}")
async with aopen(config_file, mode="r") as f:
Expand All @@ -89,7 +90,7 @@ async def load_remote_conf_def(

async def resolve_remote_config(
db: str, dc: str, skip_src: bool = False, skip_dst: bool = False
) -> DbupgradeConfig | None:
) -> Optional[DbupgradeConfig]:
"""
Loads the referenced remote configuration json file, tries to import the
specified resolver class, executes its resolve method, and returns the
Expand Down
Loading