Compare commits

...

2 Commits

1
.gitignore vendored

@ -13,6 +13,7 @@ __pycache__/
# Distribution / packaging
.Python
env/
*_env/
venv/
pypyenv/
build/

@ -1,5 +0,0 @@
black
flake8
pytest
pytest-cov
pip-tools

@ -4,6 +4,15 @@ A websocket service for fo use in the gears application.
# Development
It is helpful to have a clean virtualenv:
```
python -m venv gears_sockets_env
source gears_sockets_env/bin/activate
```
DO NOT add this to version control
# Testing

@ -2,12 +2,16 @@
API for the gears application
## First time setup
## Development
Create a virtual environment and activate it. Now from the root project directory run `./scripts/bootstrap`. This will install `pip-tools` and sync any dependencies for the first time.
It is helpful to have a clean virtualenv:
To run the app you will need a [postgres] database. Create a development and a test database. Update the connection strings within the `gears_api.settings.toml`. At this time, if you choose to, you can remove the demo `Todo` code and replace it with your own Model. Otherwise create your first [alembic] migration using the `alembic revision --autogenerate -m "your revision message"` command. Finally, apply your first migration with `alembic upgrade head`.
```
python -m venv gears_api_env
source gears_sockets_env/bin/activate
```
To run the app you will need a [postgres] database. Create a development and a test database. Update the connection strings within the `gears_api.settings.toml`. At this time, if you choose to, you can remove the demo `Todo` code and replace it with your own Model. Otherwise create your first [alembic] migration using the `alembic revision --autogenerate -m "your revision message"` command. Finally, apply your first migration with `alembic upgrade head`.
## Running the developement server
A `manage.py` script has been included with a collection of [click] cli functions to assist in development.

@ -8,25 +8,30 @@
appdirs==1.4.3 # via black
atomicwrites==1.3.0 # via pytest
attrs==19.1.0 # via black, pytest
black==19.3b0
attrs==19.3.0 # via black, pytest
black==19.10b0
bumpversion==0.5.3
click==7.0 # via black, pip-tools
coverage==4.5.4 # via pytest-cov
entrypoints==0.3 # via flake8
flake8==3.7.8
flake8==3.7.9
importlib-metadata==0.23 # via pluggy, pytest
mccabe==0.6.1 # via flake8
more-itertools==7.2.0 # via pytest, zipp
packaging==19.2 # via pytest
pip-tools==4.1.0
pathspec==0.6.0 # via black
pip-tools==4.2.0
pluggy==0.13.0 # via pytest
py==1.8.0 # via pytest
pycodestyle==2.5.0 # via flake8
pyflakes==2.1.1 # via flake8
pyparsing==2.4.2 # via packaging
pytest-cov==2.7.1
pytest==5.2.0
six==1.12.0 # via packaging, pip-tools
pyparsing==2.4.4 # via packaging
pytest-cov==2.8.1
pytest==5.2.2
regex==2019.11.1 # via black
six==1.13.0 # via packaging, pip-tools
toml==0.10.0 # via black
typed-ast==1.4.0 # via black
wcwidth==0.1.7 # via pytest
werkzeug==0.16.0
zipp==0.6.0 # via importlib-metadata

@ -1 +1 @@
from .views import welcome
from .views import welcome

@ -17,7 +17,7 @@ def pg_utcnow(element, compiler, **kw):
return "TIMEZONE('utc', CURRENT_TIMESTAMP)"
@compiles(CreateColumn, 'postgresql')
@compiles(CreateColumn, "postgresql")
def use_identity(element, compiler, **kw):
text = compiler.visit_create_column(element, **kw)
text = text.replace("SERIAL", "INT GENERATED BY DEFAULT AS IDENTITY")

@ -3,7 +3,11 @@ from molten import App, Route, ResponseRendererMiddleware, Settings
from molten.http import HTTP_404, Request
from molten.openapi import Metadata, OpenAPIHandler, OpenAPIUIHandler
from molten.settings import SettingsComponent
from molten.contrib.sqlalchemy import SQLAlchemyMiddleware, SQLAlchemyEngineComponent, SQLAlchemySessionComponent
from molten.contrib.sqlalchemy import (
SQLAlchemyMiddleware,
SQLAlchemyEngineComponent,
SQLAlchemySessionComponent,
)
from wsgicors import CORS
from whitenoise import WhiteNoise
@ -15,9 +19,7 @@ from . import settings
get_schema = OpenAPIHandler(
metadata=Metadata(
title="gears_api",
description="API for the gears application",
version="0.0.0"
title="gears_api", description="API for the gears application", version="0.0.0"
)
)
@ -73,7 +75,7 @@ def create_app(_components=None, _middleware=None, _routes=None, _renderers=None
components=_components or components,
middleware=_middleware or middleware,
routes=_routes or routes,
renderers=_renderers or renderers
renderers=_renderers or renderers,
)
wrapped_app = CORS(wrapped_app, **settings.strict_get("wsgicors"))
wrapped_app = WhiteNoise(wrapped_app, **settings.strict_get("whitenoise"))

@ -20,13 +20,12 @@ class BaseManager(metaclass=ABCMeta):
"""Converts a SQLAlchemy results proxy into a Schema instance"""
pass
def raise_409(self, id:int):
def raise_409(self, id: int):
"""Raises a 409 HTTP error response in the event of Conflict"""
raise HTTPError(
HTTP_409,
{
"status": 409,
"message": f"Entity {self.__class__.__name__} with id: {id} already exists"
}
"message": f"Entity {self.__class__.__name__} with id: {id} already exists",
},
)

@ -47,7 +47,9 @@ def initdb():
"""
Initialize database
"""
click.echo("This feature has been commented out. Please use alembic to manage your database initialization and changes.")
click.echo(
"This feature has been commented out. Please use alembic to manage your database initialization and changes."
)
# from gears_api.db import Base
#
# def _init(engine_data: EngineData):

@ -1,7 +1,9 @@
"""isort:skip_file
"""
import os
import sys; sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..")) # noqa
import sys
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..")) # noqa
from alembic import context
from gears_api.index import create_app
@ -18,4 +20,4 @@ def run_migrations_online(engine_data: EngineData):
context.run_migrations()
app.injector.get_resolver().resolve(run_migrations_online)()
app.injector.get_resolver().resolve(run_migrations_online)()

@ -10,7 +10,7 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'dc04b852fef5'
revision = "dc04b852fef5"
down_revision = None
branch_labels = None
depends_on = None

@ -2,23 +2,31 @@
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile gears_api/requirements.in
# pip-compile requirements.in
#
--trusted-host pypi.python.org
alembic==1.2.1
alembic==1.3.0
authlib==0.12.1 # via molten-jwt
cffi==1.13.2 # via cryptography
click==7.0
gunicorn==19.9.0
cryptography==2.8 # via authlib
gunicorn==20.0.0
mako==1.1.0 # via alembic
markupsafe==1.1.1 # via mako
molten-jwt==0.3.0
molten==0.7.4
mypy-extensions==0.4.2 # via typing-inspect
psycopg2-binary==2.8.3
python-dateutil==2.8.0 # via alembic
mypy-extensions==0.4.3 # via typing-inspect
psycopg2-binary==2.8.4
pycparser==2.19 # via cffi
python-dateutil==2.8.1 # via alembic
python-editor==1.0.4 # via alembic
six==1.12.0 # via python-dateutil
sqlalchemy==1.3.9
typing-extensions==3.7.4 # via molten
six==1.13.0 # via cryptography, python-dateutil
sqlalchemy==1.3.10
typing-extensions==3.7.4.1 # via molten
typing-inspect==0.3.1 # via molten
whitenoise==4.1.4
wsgicors==0.7.0
# The following packages are considered to be unsafe in a requirements file:
# setuptools==41.6.0 # via gunicorn

@ -0,0 +1,10 @@
[bumpversion]
current_version = 0.1.0
[bumpversion:file:setup.py]
search = version='{current_version}'
replace = {new_version}
[bumpversion:file:gears_api/__init__.py]
search = __version__ = '{current_version}'
replace = {new_version}

@ -7,12 +7,14 @@ from gears_api.index import create_app
def truncate_all_tables(session: Session):
table_names = session.execute("""
table_names = session.execute(
"""
select table_name from information_schema.tables
where table_schema = 'public'
and table_type = 'BASE TABLE'
and table_name != 'alembic_version'
""")
"""
)
for (table_name,) in table_names:
# "truncate" can deadlock so we use delete which is guaranteed not to.
session.execute(f"delete from {table_name}")
@ -47,5 +49,7 @@ def load_component(app):
def load(annotation):
def loader(c: annotation):
return c
return app.injector.get_resolver().resolve(loader)()
return load

@ -16,8 +16,8 @@ def test_insert_todo(client):
response = client.post("/todos", data=payload)
content = response.json()
assert response.status_code == 201
assert type(content['id']) == int
assert content['todo'] == payload['todo']
assert type(content["id"]) == int
assert content["todo"] == payload["todo"]
def test_get_individual_todo_by_href(client):
@ -34,7 +34,9 @@ def test_update_todo(client):
payload = {"todo": "sample app"}
response = client.post("/todos", json=payload)
todo = response.json()
update_response = client.patch("{}".format(todo.get("href")), json={"complete": True, "todo": "sample app"})
update_response = client.patch(
"{}".format(todo.get("href")), json={"complete": True, "todo": "sample app"}
)
updated_todo = update_response.json()
assert updated_todo["complete"] == True

@ -11,5 +11,5 @@ def test_extended_encoder_date_parsing():
def test_extended_encoder_decimal_casting():
json_renderer = ExtJSONRenderer()
test_decimal = Decimal('1.0')
test_decimal = Decimal("1.0")
assert 1.0 == json_renderer.default(test_decimal)

Loading…
Cancel
Save