Skip to content
This repository has been archived by the owner on Oct 26, 2024. It is now read-only.

Commit

Permalink
Merge pull request #4 from dwreeves/updates
Browse files Browse the repository at this point in the history
updates
  • Loading branch information
dwreeves authored May 26, 2024
2 parents 8c1ddce + 2f2c779 commit 8eb28f2
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 58 deletions.
39 changes: 14 additions & 25 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,8 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python: [3.6.x, 3.7.x, 3.8.x, 3.9.x, 3.10.x, 3.11.x]
flask: [2.0.*, 2.*]
click: [7.*, 8.*]
psycopg: [psycopg2]
flask-sqlalchemy: [2.*, 3.*]
exclude:
- flask: 2.*
flask-sqlalchemy: 3.*
- python: 3.6.x
flask-sqlalchemy: 3.*
- flask: 2.*
click: 7.*
- python: 3.6.x
flask: 2.*
python: [3.8.x, 3.12.x]
psycopg: [psycopg2, psycopg]
services:
postgres:
image: postgres:12-alpine
Expand All @@ -47,19 +35,20 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install python-dev libpq-dev
pip install --upgrade pip
make install
pip install --upgrade flask=="${FLASK_VERSION}"
pip install --upgrade click=="${CLICK_VERSION}"
pip install --upgrade flask-sqlalchemy=="${FLASK_SQLALCHEMY_VERSION}"
pip install "${PSYCOPG_PACKAGE}"
sudo apt-get install libpq-dev
pip install --upgrade pip uv
uv pip install --system --extra test -r pyproject.toml
uv pip install --system "${PSYCOPG_PACKAGE}"
env:
FLASK_VERSION: ${{ matrix.flask }}
FLASK_SQLALCHEMY_VERSION: ${{ matrix.flask-sqlalchemy }}
CLICK_VERSION: ${{ matrix.click }}
PSYCOPG_PACKAGE: ${{ matrix.psycopg }}
- name: Run tests
run: make test
env:
TEST_DATABASE_URI: postgresql://postgres:postgres@localhost:5432/flask_postgres_test_database
TEST_DATABASE_URI: postgresql+${{ matrix.psycopg }}://postgres:postgres@localhost:5432/flask_postgres_test_database
# - name: "Run tests (resolution: lowest)"
# run: |
# uv pip install --system --upgrade --resolution lowest-direct -r pyproject.toml
# uv pip install --system --upgrade "werkzeug<3"
# make test
# env:
# TEST_DATABASE_URI: postgresql+${{ matrix.psycopg }}://postgres:postgres@localhost:5432/flask_postgres_test_database
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
.PHONY: install
install:
# Deprecated; using uv instead:
# pip install uv
# uv pip install --system --extra test -r pyproject.toml
# uv pip install --system psycopg2
# export TEST_DATABASE_URI=postgresql+psycopg2://postgres:postgres@postgres:5432/flask_postgres_test_database
pip install flit
flit install --deps develop --symlink

Expand Down
53 changes: 53 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
services:

python:
image: python:3.10
tty: true
links:
- postgres
networks:
- db
volumes:
- .:/usr/flask-postgres
working_dir: /usr/flask-postgres
command:
- "/bin/bash"

postgres:
image: postgres:16
environment:
POSTGRES_USER: postgres
POSTGRES_HOST: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: mydb
tty: true
ports:
- "5432:5432"
networks:
- db
volumes:
- postgres:/var/lib/postgresql/data

pgadmin:
image: dpage/pgadmin4
depends_on:
- postgres
networks:
- db
ports:
- "5051:5050"
volumes:
- pgadmin:/var/lib/pgadmin
environment:
PGADMIN_DEFAULT_EMAIL: admin@admin.com
PGADMIN_DEFAULT_PASSWORD: admin


networks:
db:
driver: bridge


volumes:
postgres: {}
pgadmin: {}
2 changes: 1 addition & 1 deletion flask_postgres/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
from .ops import drop_db
from .types import PostgresUri

__version__ = "0.2.3"
__version__ = "0.2.4"
8 changes: 4 additions & 4 deletions flask_postgres/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@

def get_connection(
ctx: click.Context,
uri: str
uri: dict
) -> "psycopg.Connection":
conn = psycopg.connect(uri)
conn = psycopg.connect(**uri)
conn.autocommit = True
ctx.call_on_close(conn.close)
return conn
Expand Down Expand Up @@ -160,7 +160,7 @@ def create_db_command(
if overwrite:
ctx.forward(drop_db_command)
admin_uri = uri.admin_uri(admin_dbname)
conn = get_connection(ctx, admin_uri)
conn = get_connection(ctx, admin_uri.connection_dict())
return create_db(
conn=conn,
dbname=uri.dbname,
Expand Down Expand Up @@ -206,7 +206,7 @@ def drop_db_command(
):
"""Delete the database."""
admin_uri = uri.admin_uri(admin_dbname)
conn = get_connection(ctx, admin_uri)
conn = get_connection(ctx, admin_uri.connection_dict())
return drop_db(
conn=conn,
dbname=uri.dbname,
Expand Down
36 changes: 25 additions & 11 deletions flask_postgres/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@


_db_regex = re.compile(
r'(?:(?P<scheme>[a-z][a-z0-9+\-.]+(?:\+[a-z0-9+\-.]+)?)://)?'
r'(?:(?P<scheme>[a-z][a-z0-9\-.]+)(?:\+(?P<driver>[a-z0-9+\-.]+))?://)?'
r'(?:(?P<user>[^\s:/]*)'
r'(?::(?P<password>[^\s/]*))?@)?'
r'(?P<host>[^\s/:?#]+)'
Expand All @@ -21,6 +21,7 @@

class _PsqlUriParts(t.NamedTuple):
scheme: str
driver: t.Optional[str]
user: t.Optional[str]
password: t.Optional[str]
host: str
Expand All @@ -44,6 +45,7 @@ def __init__(
uri: t.Optional[str] = None,
*,
scheme: str = "postgresql",
driver: t.Optional[str] = "postgresql",
user: t.Optional[str] = None,
password: t.Optional[str] = None,
host: str = "localhost",
Expand All @@ -53,17 +55,19 @@ def __init__(
if uri is None:
self.build(
scheme=scheme,
driver=driver,
user=user,
password=password,
host=host,
port=port,
dbname=dbname
)
else:
scheme, user, password, host, port, dbname = \
scheme, driver, user, password, host, port, dbname = \
self._parts_from_str(uri)
str.__init__(uri)
self.scheme = scheme
self.driver = driver
self.user = user
self.password = password
self.host = host
Expand All @@ -73,6 +77,7 @@ def __init__(
self.validate(
uri=uri,
scheme=scheme,
driver=driver,
user=user,
password=password,
host=host,
Expand Down Expand Up @@ -108,6 +113,7 @@ def _parts_from_str(
)
return _PsqlUriParts(
scheme=match_obj.group("scheme"),
driver=match_obj.group("driver"),
user=match_obj.group("user"),
password=match_obj.group("password"),
host=match_obj.group("host"),
Expand All @@ -117,16 +123,20 @@ def _parts_from_str(

@classmethod
def build(
cls,
*,
scheme: str = "postgresql",
user: t.Optional[str] = None,
password: t.Optional[str] = None,
host: str = "localhost",
port: t.Optional[t.Union[str, int]] = 5432,
dbname: str,
cls,
*,
scheme: str = "postgresql",
driver: t.Optional[str] = None,
user: t.Optional[str] = None,
password: t.Optional[str] = None,
host: str = "localhost",
port: t.Optional[t.Union[str, int]] = 5432,
dbname: str,
) -> str:
uri = f"{scheme}://"
uri = scheme
if driver is not None:
uri += f"+{driver}"
uri += "://"
if user is not None:
uri += user
if password is not None:
Expand All @@ -145,6 +155,7 @@ def validate(
uri: str,
*,
scheme: str = "postgresql",
driver: t.Optional[str] = None,
user: t.Optional[str] = None,
password: t.Optional[str] = None,
host: str = "localhost",
Expand Down Expand Up @@ -187,6 +198,9 @@ def default(cls) -> "PostgresUri":
def dict(self) -> t.Dict[str, t.Optional[t.Union[str, int]]]:
return {i: getattr(self, i) for i in self.__slots__}

def connection_dict(self) -> t.Dict[str, t.Optional[t.Union[str, int]]]:
return {k: v for k, v in self.dict().items() if k in {"dbname", "user", "password", "host", "port"}}

def admin_uri(self, dbname: t.Optional[str] = None) -> "PostgresUri":
d = self.dict()
dbname = dbname or config.get("FLASK_POSTGRES_ADMIN_DBNAME")
Expand Down
10 changes: 5 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ classifiers = [
"Topic :: Database"
]
requires = [
"Flask>=1.0",
"Flask>=2.0",
"Click>=7.0",
"SQLAlchemy>=1.2.2",
"Flask-SQLAlchemy>=2.4",
"SQLAlchemy>=1.4.0",
"Flask-SQLAlchemy>=2.5",
]
requires-python = ">=3.6"
requires-python = ">=3.7"

[tool.flit.metadata.requires-extra]
test = [
"psycopg",
# "psycopg2",
"pytest>=6.0.1,<7a0",
"pytest-cov",
"pytest-postgresql",
Expand Down
24 changes: 12 additions & 12 deletions tests/test_cli_normal_app_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ def test_psql_create_command(

assert not db_exists(admin_connection, dbname)

client = typically_configured_app.test_cli_runner()
res = client.invoke(typically_configured_app.cli, ["psql", "create"])
client = typically_configured_app.test_cli_runner(mix_stderr=True)
res: Result = client.invoke(typically_configured_app.cli, ["psql", "create"])

assert res.exit_code == 0
assert res.exit_code == 0, res.output
assert res.output == f'database "{dbname}" was created\n'
assert db_exists(admin_connection, dbname)

Expand All @@ -84,7 +84,7 @@ def test_psql_init_command(
db_inspector = sa.inspect(db.engine)
assert not db_inspector.has_table("pet")

client = typically_configured_app.test_cli_runner()
client = typically_configured_app.test_cli_runner(mix_stderr=True)
res = client.invoke(typically_configured_app.cli, ["psql", "init"])

assert res.exit_code == 0, res.output
Expand All @@ -110,7 +110,7 @@ def test_psql_init_command_when_db_not_created(

assert not db_exists(admin_connection, dbname)

client = typically_configured_app.test_cli_runner()
client = typically_configured_app.test_cli_runner(mix_stderr=True)
res = client.invoke(typically_configured_app.cli, ["psql", "init"])

assert res.output == f'database "{dbname}" does not exist\n', res.output
Expand All @@ -127,7 +127,7 @@ def test_psql_init_command_with_custom_callback(
):
dbname = db_params.get("dbname")

client = typically_configured_app.test_cli_runner()
client = typically_configured_app.test_cli_runner(mix_stderr=True)
res = client.invoke(typically_configured_app.cli, ["psql", "init"])

assert res.exit_code == 0, res.output
Expand Down Expand Up @@ -168,7 +168,7 @@ def test_psql_drop_command(
else:
input_stream = None

client = typically_configured_app.test_cli_runner()
client = typically_configured_app.test_cli_runner(mix_stderr=True)
res = client.invoke(
typically_configured_app.cli,
["psql", "drop", *cli_test_conf.options],
Expand Down Expand Up @@ -199,7 +199,7 @@ def test_psql_drop_command_wont_delete_on_typo(

input_stream = uri + "extratext"

client = typically_configured_app.test_cli_runner()
client = typically_configured_app.test_cli_runner(mix_stderr=True)
res = client.invoke(
typically_configured_app.cli,
["psql", "drop"],
Expand All @@ -226,7 +226,7 @@ def test_psql_setup_command(

assert not db_exists(admin_connection, dbname)

client = typically_configured_app.test_cli_runner()
client = typically_configured_app.test_cli_runner(mix_stderr=True)
res = client.invoke(typically_configured_app.cli, ["psql", "setup"])

assert res.exit_code == 0, res.output
Expand Down Expand Up @@ -254,7 +254,7 @@ def test_psql_setup_command_with_custom_callback(

assert not db_exists(admin_connection, dbname)

client = typically_configured_app.test_cli_runner()
client = typically_configured_app.test_cli_runner(mix_stderr=True)
res = client.invoke(typically_configured_app.cli, ["psql", "setup"])

assert res.exit_code == 0, res.output
Expand Down Expand Up @@ -286,7 +286,7 @@ def test_psql_setup_command_when_db_exists(
db_inspector = sa.inspect(db.engine)
assert not db_inspector.has_table("pet")

client = typically_configured_app.test_cli_runner()
client = typically_configured_app.test_cli_runner(mix_stderr=True)
res = client.invoke(typically_configured_app.cli, ["psql", "setup"])

assert res.exit_code == 0, res.output
Expand Down Expand Up @@ -318,7 +318,7 @@ def test_psql_reset_command(

assert db_exists(admin_connection, dbname)

client = typically_configured_app.test_cli_runner()
client = typically_configured_app.test_cli_runner(mix_stderr=True)
res = client.invoke(typically_configured_app.cli, ["psql", "reset", "-f"])

assert res.exit_code == 0, res.output
Expand Down
Loading

0 comments on commit 8eb28f2

Please sign in to comment.