From 68352f02606b3dff22fa3555b4dc00b86ab5c56c Mon Sep 17 00:00:00 2001 From: Nil-Andreu Date: Sat, 14 Jan 2023 18:10:10 +0100 Subject: [PATCH 1/3] [NEW] Pre-commit config --- .pre-commit-config.yaml | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..81520b7 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,42 @@ +files: src + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: trailing-whitespace + - id: check-ast + - id: check-yaml + - id: check-json + - id: check-case-conflict + - id: detect-private-key + - id: fix-encoding-pragma + args: [--remove] + - id: forbid-submodules + - id: mixed-line-ending + - id: requirements-txt-fixer + - id: check-executables-have-shebangs + - id: check-shebang-scripts-are-executable + - id: check-byte-order-marker + - id: check-symlinks + - id: check-merge-conflict + - id: check-added-large-files + args: [--maxkb=1024] + - id: end-of-file-fixer + - id: double-quote-string-fixer + + - repo: https://github.com/pycqa/flake8 + rev: 6.0.0 + hooks: + - id: flake8 + + - repo: https://github.com/pycqa/isort + rev: 5.11.1 + hooks: + - id: isort + + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v2.7.1 + hooks: + - id: prettier + args: [--prose-wrap=always, --write] \ No newline at end of file From 08e95879bae298948c3e1a203eaee087e3646889 Mon Sep 17 00:00:00 2001 From: Nil-Andreu Date: Sat, 14 Jan 2023 18:10:23 +0100 Subject: [PATCH 2/3] [NEW] Setup cfg --- setup.cfg | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 setup.cfg diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..173dbd7 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,3 @@ +[flake8] +max-line-length = 126 +extend-ignore = E203, W503, E501, E741, F841, F401, F821 \ No newline at end of file From cd55122d653d19a31e49679fb18f057d613fc378 Mon Sep 17 00:00:00 2001 From: Nil-Andreu Date: Sat, 14 Jan 2023 18:10:32 +0100 Subject: [PATCH 3/3] [NEW] Applying pre-commit --- README.md | 14 ++++++++ src/app/api/crud.py | 2 +- src/app/api/notes.py | 28 ++++++++-------- src/app/api/ping.py | 4 +-- src/app/db.py | 26 +++++---------- src/app/main.py | 6 ++-- src/requirements.txt | 10 +++--- src/tests/conftest.py | 2 +- src/tests/test_notes.py | 74 ++++++++++++++++++++--------------------- src/tests/test_ping.py | 4 +-- 10 files changed, 88 insertions(+), 82 deletions(-) diff --git a/README.md b/README.md index f72c106..84d6d5c 100644 --- a/README.md +++ b/README.md @@ -17,3 +17,17 @@ Test out the following routes: 1. [http://localhost:8002/ping](http://localhost:8002/ping) 1. [http://localhost:8002/docs](http://localhost:8002/docs) 1. [http://localhost:8002/notes](http://localhost:8002/notes) + + +## Want to use pre-commit? +For using the pre-commit, you should go inside of the `src` folder: +```bash + # Create the environment + python3 -m venv venv + + # Activate the environment + source env/bin/activate + + # Install pre-commit + pip3 install pre-commit +``` \ No newline at end of file diff --git a/src/app/api/crud.py b/src/app/api/crud.py index 3c9c33f..ee3a970 100644 --- a/src/app/api/crud.py +++ b/src/app/api/crud.py @@ -1,5 +1,5 @@ from app.api.models import NoteSchema -from app.db import notes, database +from app.db import database, notes async def post(payload: NoteSchema): diff --git a/src/app/api/notes.py b/src/app/api/notes.py index dc84882..4d92800 100644 --- a/src/app/api/notes.py +++ b/src/app/api/notes.py @@ -8,52 +8,52 @@ router = APIRouter() -@router.post("/", response_model=NoteDB, status_code=201) +@router.post('/', response_model=NoteDB, status_code=201) async def create_note(payload: NoteSchema): note_id = await crud.post(payload) response_object = { - "id": note_id, - "title": payload.title, - "description": payload.description, + 'id': note_id, + 'title': payload.title, + 'description': payload.description, } return response_object -@router.get("/{id}/", response_model=NoteDB) +@router.get('/{id}/', response_model=NoteDB) async def read_note(id: int = Path(..., gt=0),): note = await crud.get(id) if not note: - raise HTTPException(status_code=404, detail="Note not found") + raise HTTPException(status_code=404, detail='Note not found') return note -@router.get("/", response_model=List[NoteDB]) +@router.get('/', response_model=List[NoteDB]) async def read_all_notes(): return await crud.get_all() -@router.put("/{id}/", response_model=NoteDB) +@router.put('/{id}/', response_model=NoteDB) async def update_note(payload: NoteSchema, id: int = Path(..., gt=0),): note = await crud.get(id) if not note: - raise HTTPException(status_code=404, detail="Note not found") + raise HTTPException(status_code=404, detail='Note not found') note_id = await crud.put(id, payload) response_object = { - "id": note_id, - "title": payload.title, - "description": payload.description, + 'id': note_id, + 'title': payload.title, + 'description': payload.description, } return response_object -@router.delete("/{id}/", response_model=NoteDB) +@router.delete('/{id}/', response_model=NoteDB) async def delete_note(id: int = Path(..., gt=0)): note = await crud.get(id) if not note: - raise HTTPException(status_code=404, detail="Note not found") + raise HTTPException(status_code=404, detail='Note not found') await crud.delete(id) diff --git a/src/app/api/ping.py b/src/app/api/ping.py index dd6daf4..352df0a 100644 --- a/src/app/api/ping.py +++ b/src/app/api/ping.py @@ -3,8 +3,8 @@ router = APIRouter() -@router.get("/ping") +@router.get('/ping') async def pong(): # some async operation could happen here # example: `notes = await get_all_notes()` - return {"ping": "pong!"} + return {'ping': 'pong!'} diff --git a/src/app/db.py b/src/app/db.py index 465814b..e2c7ee2 100644 --- a/src/app/db.py +++ b/src/app/db.py @@ -1,30 +1,22 @@ import os -from sqlalchemy import ( - Column, - DateTime, - Integer, - MetaData, - String, - Table, - create_engine -) -from sqlalchemy.sql import func - from databases import Database +from sqlalchemy import (Column, DateTime, Integer, MetaData, String, Table, + create_engine) +from sqlalchemy.sql import func -DATABASE_URL = os.getenv("DATABASE_URL") +DATABASE_URL = os.getenv('DATABASE_URL') # SQLAlchemy engine = create_engine(DATABASE_URL) metadata = MetaData() notes = Table( - "notes", + 'notes', metadata, - Column("id", Integer, primary_key=True), - Column("title", String(50)), - Column("description", String(50)), - Column("created_date", DateTime, default=func.now(), nullable=False), + Column('id', Integer, primary_key=True), + Column('title', String(50)), + Column('description', String(50)), + Column('created_date', DateTime, default=func.now(), nullable=False), ) # databases query builder diff --git a/src/app/main.py b/src/app/main.py index 2533c73..6235a96 100644 --- a/src/app/main.py +++ b/src/app/main.py @@ -8,15 +8,15 @@ app = FastAPI() -@app.on_event("startup") +@app.on_event('startup') async def startup(): await database.connect() -@app.on_event("shutdown") +@app.on_event('shutdown') async def shutdown(): await database.disconnect() app.include_router(ping.router) -app.include_router(notes.router, prefix="/notes", tags=["notes"]) +app.include_router(notes.router, prefix='/notes', tags=['notes']) diff --git a/src/requirements.txt b/src/requirements.txt index 1e704df..75da911 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -1,10 +1,10 @@ -databases[postgresql]==0.6.2 -psycopg2-binary==2.9.5 -SQLAlchemy==1.4.41 asyncpg==0.27.0 +databases[postgresql]==0.6.2 fastapi==0.87.0 -uvicorn==0.20.0 +httpx==0.23.1 +psycopg2-binary==2.9.5 # dev pytest==7.2.0 -httpx==0.23.1 +SQLAlchemy==1.4.41 +uvicorn==0.20.0 diff --git a/src/tests/conftest.py b/src/tests/conftest.py index a1e0294..615da60 100644 --- a/src/tests/conftest.py +++ b/src/tests/conftest.py @@ -4,7 +4,7 @@ from app.main import app -@pytest.fixture(scope="module") +@pytest.fixture(scope='module') def test_app(): client = TestClient(app) yield client # testing happens here diff --git a/src/tests/test_notes.py b/src/tests/test_notes.py index 0b02262..7f2c208 100644 --- a/src/tests/test_notes.py +++ b/src/tests/test_notes.py @@ -6,37 +6,37 @@ def test_create_note(test_app, monkeypatch): - test_request_payload = {"title": "something", "description": "something else"} - test_response_payload = {"id": 1, "title": "something", "description": "something else"} + test_request_payload = {'title': 'something', 'description': 'something else'} + test_response_payload = {'id': 1, 'title': 'something', 'description': 'something else'} async def mock_post(payload): return 1 - monkeypatch.setattr(crud, "post", mock_post) + monkeypatch.setattr(crud, 'post', mock_post) - response = test_app.post("/notes/", content=json.dumps(test_request_payload),) + response = test_app.post('/notes/', content=json.dumps(test_request_payload),) assert response.status_code == 201 assert response.json() == test_response_payload def test_create_note_invalid_json(test_app): - response = test_app.post("/notes/", content=json.dumps({"title": "something"})) + response = test_app.post('/notes/', content=json.dumps({'title': 'something'})) assert response.status_code == 422 - response = test_app.post("/notes/", content=json.dumps({"title": "1", "description": "2"})) + response = test_app.post('/notes/', content=json.dumps({'title': '1', 'description': '2'})) assert response.status_code == 422 def test_read_note(test_app, monkeypatch): - test_data = {"id": 1, "title": "something", "description": "something else"} + test_data = {'id': 1, 'title': 'something', 'description': 'something else'} async def mock_get(id): return test_data - monkeypatch.setattr(crud, "get", mock_get) + monkeypatch.setattr(crud, 'get', mock_get) - response = test_app.get("/notes/1") + response = test_app.get('/notes/1') assert response.status_code == 200 assert response.json() == test_data @@ -45,85 +45,85 @@ def test_read_note_incorrect_id(test_app, monkeypatch): async def mock_get(id): return None - monkeypatch.setattr(crud, "get", mock_get) + monkeypatch.setattr(crud, 'get', mock_get) - response = test_app.get("/notes/999") + response = test_app.get('/notes/999') assert response.status_code == 404 - assert response.json()["detail"] == "Note not found" + assert response.json()['detail'] == 'Note not found' - response = test_app.get("/notes/0") + response = test_app.get('/notes/0') assert response.status_code == 422 def test_read_all_notes(test_app, monkeypatch): test_data = [ - {"title": "something", "description": "something else", "id": 1}, - {"title": "someone", "description": "someone else", "id": 2}, + {'title': 'something', 'description': 'something else', 'id': 1}, + {'title': 'someone', 'description': 'someone else', 'id': 2}, ] async def mock_get_all(): return test_data - monkeypatch.setattr(crud, "get_all", mock_get_all) + monkeypatch.setattr(crud, 'get_all', mock_get_all) - response = test_app.get("/notes/") + response = test_app.get('/notes/') assert response.status_code == 200 assert response.json() == test_data def test_update_note(test_app, monkeypatch): - test_update_data = {"title": "someone", "description": "someone else", "id": 1} + test_update_data = {'title': 'someone', 'description': 'someone else', 'id': 1} async def mock_get(id): return True - monkeypatch.setattr(crud, "get", mock_get) + monkeypatch.setattr(crud, 'get', mock_get) async def mock_put(id, payload): return 1 - monkeypatch.setattr(crud, "put", mock_put) + monkeypatch.setattr(crud, 'put', mock_put) - response = test_app.put("/notes/1/", content=json.dumps(test_update_data)) + response = test_app.put('/notes/1/', content=json.dumps(test_update_data)) assert response.status_code == 200 assert response.json() == test_update_data @pytest.mark.parametrize( - "id, payload, status_code", + 'id, payload, status_code', [ [1, {}, 422], - [1, {"description": "bar"}, 422], - [999, {"title": "foo", "description": "bar"}, 404], - [1, {"title": "1", "description": "bar"}, 422], - [1, {"title": "foo", "description": "1"}, 422], - [0, {"title": "foo", "description": "bar"}, 422], + [1, {'description': 'bar'}, 422], + [999, {'title': 'foo', 'description': 'bar'}, 404], + [1, {'title': '1', 'description': 'bar'}, 422], + [1, {'title': 'foo', 'description': '1'}, 422], + [0, {'title': 'foo', 'description': 'bar'}, 422], ], ) def test_update_note_invalid(test_app, monkeypatch, id, payload, status_code): async def mock_get(id): return None - monkeypatch.setattr(crud, "get", mock_get) + monkeypatch.setattr(crud, 'get', mock_get) - response = test_app.put(f"/notes/{id}/", content=json.dumps(payload),) + response = test_app.put(f'/notes/{id}/', content=json.dumps(payload),) assert response.status_code == status_code def test_remove_note(test_app, monkeypatch): - test_data = {"title": "something", "description": "something else", "id": 1} + test_data = {'title': 'something', 'description': 'something else', 'id': 1} async def mock_get(id): return test_data - monkeypatch.setattr(crud, "get", mock_get) + monkeypatch.setattr(crud, 'get', mock_get) async def mock_delete(id): return id - monkeypatch.setattr(crud, "delete", mock_delete) + monkeypatch.setattr(crud, 'delete', mock_delete) - response = test_app.delete("/notes/1/") + response = test_app.delete('/notes/1/') assert response.status_code == 200 assert response.json() == test_data @@ -132,11 +132,11 @@ def test_remove_note_incorrect_id(test_app, monkeypatch): async def mock_get(id): return None - monkeypatch.setattr(crud, "get", mock_get) + monkeypatch.setattr(crud, 'get', mock_get) - response = test_app.delete("/notes/999/") + response = test_app.delete('/notes/999/') assert response.status_code == 404 - assert response.json()["detail"] == "Note not found" + assert response.json()['detail'] == 'Note not found' - response = test_app.delete("/notes/0/") + response = test_app.delete('/notes/0/') assert response.status_code == 422 diff --git a/src/tests/test_ping.py b/src/tests/test_ping.py index 4dcf453..48e0b3a 100644 --- a/src/tests/test_ping.py +++ b/src/tests/test_ping.py @@ -1,4 +1,4 @@ def test_ping(test_app): - response = test_app.get("/ping") + response = test_app.get('/ping') assert response.status_code == 200 - assert response.json() == {"ping": "pong!"} + assert response.json() == {'ping': 'pong!'}