Cappa

Cappa

Actions Status Coverage Status Documentation Status

Cappa is a declarative command line parsing library, taking much of its inspiration from the “Derive” API from the Clap written in Rust.

from dataclasses import dataclass, field
import cappa
from typing import Literal
from typing_extensions import Annotated


@dataclass
class Example:
    positional_arg: str = "optional"
    boolean_flag: bool = False
    single_option: Annotated[int | None, cappa.Arg(short=True, help="A number")] = None
    multiple_option: Annotated[
        list[Literal["one", "two", "three"]],
        cappa.Arg(long=True, help="Pick one!"),
    ] = field(default_factory=list)


args: Example = cappa.parse(Example, backend=cappa.backend)
print(args)

Produces the following CLI:

help text

In this way, you can turn any dataclass-like object (with some additional annotations, depending on what you’re looking for) into a CLI.

...

September 23, 2023 · 3 min · Dan Cardin

SQLAlchemy Declarative Extensions

A python library for adding extensions to SqlAlchemy (and/or Alembic) which allows declaratively stating the existence of additional kinds of objects about your database not natively supported by SqlAlchemy/Alembic.

@declarative_database
@as_declarative
class Base:
    schemas = Schemas().are("example")
    roles = Roles(ignore_unspecified=True).are(
        Role("read", login=False),
        Role(
            "app",
            in_roles=['read']
        ),
    )
    grants = Grants().are(
        DefaultGrant.on_tables_in_schema("public", 'example').grant("select", to="read"),
        DefaultGrant.on_tables_in_schema("public").grant("insert", "update", "delete", to="write"),
        DefaultGrant.on_sequences_in_schema("public").grant("usage", to="write"),
    )
    rows = Rows().are(
        Row('foo', id=1),
    )
    views = Views().are(View("low_foo", "select * from foo where i < 10"))


class Foo(Base):
    __tablename__ = 'foo'

    id = Column(types.Integer(), primary_key=True)


@view()
class HighFoo:
    __tablename__ = "high_foo"
    __view__ = select(Foo.__table__).where(Foo.__table__.c.id >= 10)

December 1, 2022 · 1 min · Dan Cardin

Pytest Alembic

A Pytest plugin to test alembic migrations (with default tests) and which enables you to write tests specific to your migrations.

$ pip install pytest-alembic
$ pytest --test-alembic

...
::pytest_alembic/tests/model_definitions_match_ddl <- . PASSED           [ 25%]
::pytest_alembic/tests/single_head_revision <- . PASSED                  [ 50%]
::pytest_alembic/tests/up_down_consistency <- . PASSED                   [ 75%]
::pytest_alembic/tests/upgrade <- . PASSED                               [100%]

============================== 4 passed in 2.32s ===============================

February 29, 2020 · 1 min · Dan Cardin

Chapter Sync

A tool for recording serialized web content, in partial web-serial type novels, or other serialized content for which you want to be sent updates as they’re published.

The other tools in the space (at least that I’m aware of: Leech, FanFicFare) are mostly designed around manual one-off usage of the tool to capture the current state of a story/series and turn it into an ebook.

chapter-sync, by contrast, records everything it captures to a sqlite database and will only collect new/missing chapters. It also bakes in (through supported subscription methods) the ability to send new chapters to “subscribers” who have not yet received it.

February 27, 2024 · 1 min · Dan Cardin

Dataclass Settings

A declarative settings library

dataclass-settings intends to work with any PEP-681-compliant dataclass-like object, including but not limited to:

  • Pydantic models (v2+)
  • dataclasses
  • attrs classes
from __future__ import annotations
from dataclass_settings import load_settings, Env, Secret
from pydantic import BaseModel


class Example(BaseModel):
    env: Annotated[str, Env("ENVIRONMENT")] = "local"
    dsn: Annotated[str, Env("DSN"), Secret('dsn')] = "dsn://"

    sub_config: SubConfig


class SubConfig(BaseModel):
    nested: Annotated[int, Env("NESTED")] = "4"


example: Example = load_settings(Example)

# or, if you want `nested` to be `SUB_CONFIG_NESTED`
example: Example = load_settings(Example, nested_delimiter='_')

October 29, 2023 · 1 min · Dan Cardin

Pytest Mock Resources

A python library which produces pytest fixtures which let you test against external resource (Postgres, Mongo, Redshift…) dependent code, by orchestrating running real instances of those services.

from pytest_mock_resources import create_postgres_fixture
from models import ModelBase

pg = create_postgres_fixture(ModelBase, session=True)

def test_view_function_empty_db(pg):
  response = view_function(pg)
  assert response == ...

January 9, 2019 · 1 min · Dan Cardin

Sauce

A tool to help manage context/project specific shell-things like environment variables.

# Suppose you've got some directory structure
❯ mkdir -p projects/foo
cd projects

# In "projects", you want some shorthand for quickly pushing your branches
❯ sauce new
Created /Users/danc/.local/share/sauce/projects.toml

❯ sauce set alias push='git push origin "$(git rev-parse --abbrev-ref HEAD)"'
Setting push = git push origin "$(git rev-parse --abbrev-ref HEAD)"

# Your project is, naturally, using 12-factor methodology, so you've got some
# project specific environment variables you need to load!
cd foo
❯ sauce set env foo=bar AWS_PROFILE=meow
Setting foo = bar
Setting AWS_PROFILE = meow

# The core purpose!
❯ sauce
Sourced ~/.local/share/sauce/projects/foo.toml

❯ env
...
AWS_PROFILE=meow
foo=bar

January 23, 2021 · 1 min · Dan Cardin

Databudgie

Databudgie is a CLI & library for database performing targeted backup and restore of database tables or arbitrary queries against database tables.

Some minimal config might look like:

# config.databudgie.yml
backup:
  url: postgresql://postgres:postgres@localhost:5432/postgres

restore:
  url: postgresql://postgres:postgres@localhost:5432/postgres

tables:
  - some_schema.*
  - author
  - book
  - name: chapter
    query: "select * from {table} where book_id > 4"
  - name: some_table
    follow_foreign_keys: true

Think pg_dump, but more flexible and easy to produce backups for a targeted set of tables/data, and restore them.

October 10, 2019 · 1 min · Dan Cardin

SQLAlchemy Model Factory

A python library which makes it easy to write factory functions for sqlalchemy models, particularly for use in testing.

The most obvious comparison is against the much more popular python library, FactoryBoy. By comparison, SQLAlchemy Model Factory removes a lot of the magic and machinery introduced by factory boy.

One essentially writes regular functions, (which are directly callable as functions!), which when called through the “ModelFactory” (mf by default) fixture, automatically produces those objects in the database, similarly to FactoryBoy.

...

1 min · Dan Cardin

Configly

A python library to simplify and centralize the loading of configuration, such as environment variables.

# config.yml
foo:
  bar: <% ENV[REQUIRED] %>
  baz: <% ENV[OPTIONAL, true] %>
list_of_stuff:
  - fun<% ENV[NICE, dament] %>al
  - fun<% ENV[AGH, er] %>al
# app.py
config = Config.from_yaml('config.yml')

print(config.foo.bar)
print(config.foo['baz'])
for item in config.list_of_stuff:
    print(item)

September 23, 2019 · 1 min · Dan Cardin