24 |
Todo ID: {{ todo.id }}
25 |26 | 27 | Item: {{ todo.item }} 28 | 29 |
30 |├── ch05 └── planner │ ├── database │ └── __init__.py │ ├── models │ ├── __init__.py │ ├── __pycache__ │ │ ├── events.cpython-310.pyc │ │ ├── users.cpython-310.pyc │ │ └── __init__.cpython-310.pyc │ ├── events.py │ └── users.py │ ├── routes │ ├── __init__.py │ ├── __pycache__ │ │ ├── events.cpython-310.pyc │ │ ├── users.cpython-310.pyc │ │ └── __init__.cpython-310.pyc │ ├── users.py │ └── events.py │ ├── __pycache__ │ └── main.cpython-310.pyc │ ├── main.py │ └── requirements.txt ├── ch06 └── planner │ ├── database │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-310.pyc │ │ └── connection.cpython-310.pyc │ └── connection.py │ ├── models │ ├── __init__.py │ ├── __pycache__ │ │ ├── events.cpython-310.pyc │ │ ├── users.cpython-310.pyc │ │ └── __init__.cpython-310.pyc │ ├── users.py │ └── events.py │ ├── routes │ ├── __init__.py │ ├── __pycache__ │ │ ├── events.cpython-310.pyc │ │ ├── users.cpython-310.pyc │ │ └── __init__.cpython-310.pyc │ ├── users.py │ └── events.py │ ├── __pycache__ │ └── main.cpython-310.pyc │ ├── requirements.txt │ └── main.py ├── ch07 └── planner │ ├── auth │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-310.pyc │ │ ├── jwt_handler.cpython-310.pyc │ │ ├── authenticate.cpython-310.pyc │ │ └── hash_password.cpython-310.pyc │ ├── hash_password.py │ ├── authenticate.py │ └── jwt_handler.py │ ├── database │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-310.pyc │ │ └── connection.cpython-310.pyc │ └── connection.py │ ├── models │ ├── __init__.py │ ├── __pycache__ │ │ ├── events.cpython-310.pyc │ │ ├── users.cpython-310.pyc │ │ └── __init__.cpython-310.pyc │ ├── users.py │ └── events.py │ ├── routes │ ├── __init__.py │ ├── __pycache__ │ │ ├── events.cpython-310.pyc │ │ ├── users.cpython-310.pyc │ │ └── __init__.cpython-310.pyc │ ├── users.py │ └── events.py │ ├── __pycache__ │ └── main.cpython-310.pyc │ ├── requirements.txt │ └── main.py ├── ch08 └── planner │ ├── auth │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-310.pyc │ │ ├── jwt_handler.cpython-310.pyc │ │ ├── authenticate.cpython-310.pyc │ │ └── hash_password.cpython-310.pyc │ ├── hash_password.py │ ├── authenticate.py │ └── jwt_handler.py │ ├── database │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-310.pyc │ │ └── connection.cpython-310.pyc │ └── connection.py │ ├── models │ ├── __init__.py │ ├── __pycache__ │ │ ├── events.cpython-310.pyc │ │ ├── users.cpython-310.pyc │ │ └── __init__.cpython-310.pyc │ ├── users.py │ └── events.py │ ├── routes │ ├── __init__.py │ ├── __pycache__ │ │ ├── events.cpython-310.pyc │ │ ├── users.cpython-310.pyc │ │ └── __init__.cpython-310.pyc │ ├── users.py │ └── events.py │ ├── pytest.ini │ ├── htmlcov │ ├── favicon_32.png │ ├── keybd_closed.png │ ├── keybd_open.png │ ├── status.json │ ├── d_e634d7a1dd90e049___init___py.html │ ├── d_60afb0a4f41d540c___init___py.html │ ├── d_f244bf8a352cf537___init___py.html │ ├── d_c44ac6e9bb193d64___init___py.html │ ├── d_60afb0a4f41d540c_hash_password_py.html │ ├── d_60afb0a4f41d540c_authenticate_py.html │ ├── d_a44f0ac069e85531_test_fixture_py.html │ ├── d_e634d7a1dd90e049_users_py.html │ ├── index.html │ ├── d_a44f0ac069e85531_test_arthmetic_operations_py.html │ ├── d_a44f0ac069e85531_conftest_py.html │ └── style.css │ ├── __pycache__ │ └── main.cpython-310.pyc │ ├── tests │ ├── __pycache__ │ │ ├── conftest.cpython-310-pytest-7.2.1.pyc │ │ ├── test_fixture.cpython-310-pytest-7.2.1.pyc │ │ ├── test_login.cpython-310-pytest-7.2.1.pyc │ │ ├── test_routes.cpython-310-pytest-7.2.1.pyc │ │ └── test_arthmetic_operations.cpython-310-pytest-7.2.1.pyc │ ├── test_arthmetic_operations.py │ ├── test_fixture.py │ ├── conftest.py │ ├── test_login.py │ └── test_routes.py │ ├── main.py │ └── requirements.txt ├── ch09 └── planner │ ├── auth │ ├── __init__.py │ ├── hash_password.py │ ├── authenticate.py │ └── jwt_handler.py │ ├── database │ ├── __init__.py │ └── connection.py │ ├── models │ ├── __init__.py │ ├── users.py │ └── events.py │ ├── routes │ ├── __init__.py │ ├── users.py │ └── events.py │ ├── pytest.ini │ ├── Dockerfile │ ├── requirements.txt │ ├── docker-compose.yml │ ├── tests │ ├── test_arthmetic_operations.py │ ├── test_fixture.py │ ├── conftest.py │ ├── test_login.py │ └── test_routes.py │ └── main.py ├── ch01 ├── hello.py ├── todos │ ├── requirements.txt │ ├── __pycache__ │ │ └── api.cpython-310.pyc │ └── api.py └── Dockerfile ├── ch02 └── todos │ ├── requirements.txt │ ├── __pycache__ │ ├── api.cpython-310.pyc │ ├── model.cpython-310.pyc │ └── todo.cpython-310.pyc │ ├── api.py │ ├── model.py │ └── todo.py ├── ch03 └── todos │ ├── requirements.txt │ ├── __pycache__ │ ├── api.cpython-310.pyc │ ├── model.cpython-310.pyc │ └── todo.cpython-310.pyc │ ├── api.py │ ├── model.py │ └── todo.py ├── ch04 └── todos │ ├── requirements.txt │ ├── __pycache__ │ ├── api.cpython-310.pyc │ ├── model.cpython-310.pyc │ └── todo.cpython-310.pyc │ ├── api.py │ ├── templates │ ├── home.html │ └── todo.html │ ├── model.py │ └── todo.py └── README.md /ch05/planner/database/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch05/planner/models/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch05/planner/routes/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch06/planner/database/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch06/planner/models/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch06/planner/routes/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch07/planner/auth/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch07/planner/database/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch07/planner/models/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch07/planner/routes/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch08/planner/auth/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch08/planner/database/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch08/planner/models/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch08/planner/routes/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch09/planner/auth/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch09/planner/database/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch09/planner/models/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch09/planner/routes/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch01/hello.py: -------------------------------------------------------------------------------- 1 | print("Hello!") 2 | -------------------------------------------------------------------------------- /ch01/todos/requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi 2 | uvicorn 3 | -------------------------------------------------------------------------------- /ch08/planner/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | asyncio_mode=auto 3 | -------------------------------------------------------------------------------- /ch09/planner/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | asyncio_mode=auto 3 | -------------------------------------------------------------------------------- /ch02/todos/requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi==0.70.0 2 | uvicorn==0.15.0 3 | -------------------------------------------------------------------------------- /ch03/todos/requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi==0.70.0 2 | uvicorn==0.15.0 3 | -------------------------------------------------------------------------------- /ch04/todos/requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi==0.70.0 2 | uvicorn==0.15.0 3 | jinja2 == 3.1.2 4 | python-multipart 5 | -------------------------------------------------------------------------------- /ch08/planner/htmlcov/favicon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/htmlcov/favicon_32.png -------------------------------------------------------------------------------- /ch08/planner/htmlcov/keybd_closed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/htmlcov/keybd_closed.png -------------------------------------------------------------------------------- /ch08/planner/htmlcov/keybd_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/htmlcov/keybd_open.png -------------------------------------------------------------------------------- /ch01/todos/__pycache__/api.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch01/todos/__pycache__/api.cpython-310.pyc -------------------------------------------------------------------------------- /ch02/todos/__pycache__/api.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch02/todos/__pycache__/api.cpython-310.pyc -------------------------------------------------------------------------------- /ch03/todos/__pycache__/api.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch03/todos/__pycache__/api.cpython-310.pyc -------------------------------------------------------------------------------- /ch04/todos/__pycache__/api.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch04/todos/__pycache__/api.cpython-310.pyc -------------------------------------------------------------------------------- /ch02/todos/__pycache__/model.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch02/todos/__pycache__/model.cpython-310.pyc -------------------------------------------------------------------------------- /ch02/todos/__pycache__/todo.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch02/todos/__pycache__/todo.cpython-310.pyc -------------------------------------------------------------------------------- /ch03/todos/__pycache__/model.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch03/todos/__pycache__/model.cpython-310.pyc -------------------------------------------------------------------------------- /ch03/todos/__pycache__/todo.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch03/todos/__pycache__/todo.cpython-310.pyc -------------------------------------------------------------------------------- /ch04/todos/__pycache__/model.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch04/todos/__pycache__/model.cpython-310.pyc -------------------------------------------------------------------------------- /ch04/todos/__pycache__/todo.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch04/todos/__pycache__/todo.cpython-310.pyc -------------------------------------------------------------------------------- /ch05/planner/__pycache__/main.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch05/planner/__pycache__/main.cpython-310.pyc -------------------------------------------------------------------------------- /ch06/planner/__pycache__/main.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch06/planner/__pycache__/main.cpython-310.pyc -------------------------------------------------------------------------------- /ch07/planner/__pycache__/main.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch07/planner/__pycache__/main.cpython-310.pyc -------------------------------------------------------------------------------- /ch08/planner/__pycache__/main.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/__pycache__/main.cpython-310.pyc -------------------------------------------------------------------------------- /ch05/planner/models/__pycache__/events.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch05/planner/models/__pycache__/events.cpython-310.pyc -------------------------------------------------------------------------------- /ch05/planner/models/__pycache__/users.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch05/planner/models/__pycache__/users.cpython-310.pyc -------------------------------------------------------------------------------- /ch05/planner/routes/__pycache__/events.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch05/planner/routes/__pycache__/events.cpython-310.pyc -------------------------------------------------------------------------------- /ch05/planner/routes/__pycache__/users.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch05/planner/routes/__pycache__/users.cpython-310.pyc -------------------------------------------------------------------------------- /ch06/planner/models/__pycache__/events.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch06/planner/models/__pycache__/events.cpython-310.pyc -------------------------------------------------------------------------------- /ch06/planner/models/__pycache__/users.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch06/planner/models/__pycache__/users.cpython-310.pyc -------------------------------------------------------------------------------- /ch06/planner/routes/__pycache__/events.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch06/planner/routes/__pycache__/events.cpython-310.pyc -------------------------------------------------------------------------------- /ch06/planner/routes/__pycache__/users.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch06/planner/routes/__pycache__/users.cpython-310.pyc -------------------------------------------------------------------------------- /ch07/planner/auth/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch07/planner/auth/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /ch07/planner/models/__pycache__/events.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch07/planner/models/__pycache__/events.cpython-310.pyc -------------------------------------------------------------------------------- /ch07/planner/models/__pycache__/users.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch07/planner/models/__pycache__/users.cpython-310.pyc -------------------------------------------------------------------------------- /ch07/planner/routes/__pycache__/events.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch07/planner/routes/__pycache__/events.cpython-310.pyc -------------------------------------------------------------------------------- /ch07/planner/routes/__pycache__/users.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch07/planner/routes/__pycache__/users.cpython-310.pyc -------------------------------------------------------------------------------- /ch08/planner/auth/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/auth/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /ch08/planner/models/__pycache__/events.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/models/__pycache__/events.cpython-310.pyc -------------------------------------------------------------------------------- /ch08/planner/models/__pycache__/users.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/models/__pycache__/users.cpython-310.pyc -------------------------------------------------------------------------------- /ch08/planner/routes/__pycache__/events.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/routes/__pycache__/events.cpython-310.pyc -------------------------------------------------------------------------------- /ch08/planner/routes/__pycache__/users.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/routes/__pycache__/users.cpython-310.pyc -------------------------------------------------------------------------------- /ch05/planner/models/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch05/planner/models/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /ch05/planner/routes/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch05/planner/routes/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /ch06/planner/models/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch06/planner/models/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /ch06/planner/routes/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch06/planner/routes/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /ch07/planner/auth/__pycache__/jwt_handler.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch07/planner/auth/__pycache__/jwt_handler.cpython-310.pyc -------------------------------------------------------------------------------- /ch07/planner/models/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch07/planner/models/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /ch07/planner/routes/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch07/planner/routes/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /ch08/planner/auth/__pycache__/jwt_handler.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/auth/__pycache__/jwt_handler.cpython-310.pyc -------------------------------------------------------------------------------- /ch08/planner/models/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/models/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /ch08/planner/routes/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/routes/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /ch06/planner/database/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch06/planner/database/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /ch07/planner/auth/__pycache__/authenticate.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch07/planner/auth/__pycache__/authenticate.cpython-310.pyc -------------------------------------------------------------------------------- /ch07/planner/auth/__pycache__/hash_password.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch07/planner/auth/__pycache__/hash_password.cpython-310.pyc -------------------------------------------------------------------------------- /ch07/planner/database/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch07/planner/database/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /ch08/planner/auth/__pycache__/authenticate.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/auth/__pycache__/authenticate.cpython-310.pyc -------------------------------------------------------------------------------- /ch08/planner/auth/__pycache__/hash_password.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/auth/__pycache__/hash_password.cpython-310.pyc -------------------------------------------------------------------------------- /ch08/planner/database/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/database/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /ch06/planner/database/__pycache__/connection.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch06/planner/database/__pycache__/connection.cpython-310.pyc -------------------------------------------------------------------------------- /ch07/planner/database/__pycache__/connection.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch07/planner/database/__pycache__/connection.cpython-310.pyc -------------------------------------------------------------------------------- /ch08/planner/database/__pycache__/connection.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/database/__pycache__/connection.cpython-310.pyc -------------------------------------------------------------------------------- /ch08/planner/tests/__pycache__/conftest.cpython-310-pytest-7.2.1.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/tests/__pycache__/conftest.cpython-310-pytest-7.2.1.pyc -------------------------------------------------------------------------------- /ch08/planner/tests/__pycache__/test_fixture.cpython-310-pytest-7.2.1.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/tests/__pycache__/test_fixture.cpython-310-pytest-7.2.1.pyc -------------------------------------------------------------------------------- /ch08/planner/tests/__pycache__/test_login.cpython-310-pytest-7.2.1.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/tests/__pycache__/test_login.cpython-310-pytest-7.2.1.pyc -------------------------------------------------------------------------------- /ch08/planner/tests/__pycache__/test_routes.cpython-310-pytest-7.2.1.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/tests/__pycache__/test_routes.cpython-310-pytest-7.2.1.pyc -------------------------------------------------------------------------------- /ch01/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8 2 | # 작업 디렉터리를 /usr/src/app으로 설정한다. 3 | WORKDIR /usr/src/app 4 | # 현재 로컬 디렉터리의 파일을 컨테이너의 작업 디렉터리로 복사한다. 5 | ADD . /usr/src/app 6 | # 명령을 실행한다. 7 | CMD ["python", "hello.py"] 8 | 9 | -------------------------------------------------------------------------------- /ch01/todos/api.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | app = FastAPI() 4 | 5 | 6 | @app.get("/") 7 | async def welcome() -> dict: 8 | return { 9 | "message": "Hello World" 10 | } 11 | -------------------------------------------------------------------------------- /ch08/planner/tests/__pycache__/test_arthmetic_operations.cpython-310-pytest-7.2.1.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanbit/web-with-fastapi/HEAD/ch08/planner/tests/__pycache__/test_arthmetic_operations.cpython-310-pytest-7.2.1.pyc -------------------------------------------------------------------------------- /ch02/todos/api.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from todo import todo_router 3 | 4 | app = FastAPI() 5 | 6 | @app.get("/") 7 | async def welcome() -> dict: 8 | return { 9 | "message": "Hello World" 10 | } 11 | 12 | app.include_router(todo_router) -------------------------------------------------------------------------------- /ch09/planner/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10 2 | 3 | WORKDIR /app 4 | 5 | COPY requirements.txt /app/requirements.txt 6 | 7 | RUN pip install --upgrade pip && pip install -r /app/requirements.txt 8 | 9 | EXPOSE 8000 10 | 11 | COPY ./ /app 12 | 13 | CMD ["python", "main.py"] 14 | -------------------------------------------------------------------------------- /ch03/todos/api.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | from todo import todo_router 4 | 5 | app = FastAPI() 6 | 7 | 8 | @app.get("/") 9 | async def welcome() -> dict: 10 | return { 11 | "message": "Hello World" 12 | } 13 | 14 | 15 | app.include_router(todo_router) 16 | -------------------------------------------------------------------------------- /ch04/todos/api.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | from todo import todo_router 4 | 5 | app = FastAPI() 6 | 7 | 8 | @app.get("/") 9 | async def welcome() -> dict: 10 | return { 11 | "message": "Hello World" 12 | } 13 | 14 | 15 | app.include_router(todo_router) 16 | -------------------------------------------------------------------------------- /ch09/planner/requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi==0.78.0 2 | bcrypt==3.2.2 3 | beanie==1.11.1 4 | email-validator==1.2.1 5 | httpx==0.22.0 6 | Jinja2==3.0.3 7 | motor==2.5.1 8 | passlib==1.7.4 9 | pytest==7.1.2 10 | python-multipart==.0.0.5 11 | python-dotenv==0.20.0 12 | python-jose==3.3.0 13 | sqlmodel==0.0.6 14 | uvicorn==0.17.6 15 | 16 | -------------------------------------------------------------------------------- /ch09/planner/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | api: 5 | build: . 6 | image: event-planner-api:latest 7 | ports: 8 | - "8000:8000" 9 | env_file: 10 | - .env.prod 11 | 12 | database: 13 | image: mongo 14 | ports: 15 | - "27017" 16 | volumes: 17 | - data:/data/db 18 | 19 | volumes: 20 | data: 21 | -------------------------------------------------------------------------------- /ch07/planner/auth/hash_password.py: -------------------------------------------------------------------------------- 1 | from passlib.context import CryptContext 2 | 3 | pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") 4 | 5 | 6 | class HashPassword: 7 | def create_hash(self, password: str): 8 | return pwd_context.hash(password) 9 | 10 | def verify_hash(self, plain_password: str, hashed_password: str): 11 | return pwd_context.verify(plain_password, hashed_password) 12 | -------------------------------------------------------------------------------- /ch08/planner/auth/hash_password.py: -------------------------------------------------------------------------------- 1 | from passlib.context import CryptContext 2 | 3 | pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") 4 | 5 | 6 | class HashPassword: 7 | def create_hash(self, password: str) -> str: 8 | return pwd_context.hash(password) 9 | 10 | def verify_hash(self, plain_password: str, hashed_password: str) -> bool: 11 | return pwd_context.verify(plain_password, hashed_password) 12 | -------------------------------------------------------------------------------- /ch09/planner/auth/hash_password.py: -------------------------------------------------------------------------------- 1 | from passlib.context import CryptContext 2 | 3 | pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") 4 | 5 | 6 | class HashPassword: 7 | def create_hash(self, password: str) -> str: 8 | return pwd_context.hash(password) 9 | 10 | def verify_hash(self, plain_password: str, hashed_password: str) -> bool: 11 | return pwd_context.verify(plain_password, hashed_password) 12 | -------------------------------------------------------------------------------- /ch07/planner/models/users.py: -------------------------------------------------------------------------------- 1 | from beanie import Document 2 | 3 | from pydantic import BaseModel, EmailStr 4 | 5 | 6 | class User(Document): 7 | email: EmailStr 8 | password: str 9 | 10 | class Collection: 11 | name = "users" 12 | 13 | class Config: 14 | schema_extra = { 15 | "example": { 16 | "email": "fastapi@packt.com", 17 | "password": "strong!!!" 18 | } 19 | } 20 | 21 | 22 | class TokenResponse(BaseModel): 23 | access_token: str 24 | token_type: str 25 | -------------------------------------------------------------------------------- /ch02/todos/model.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class Todo(BaseModel): 5 | id: int 6 | item: str 7 | 8 | class Config: 9 | schema_extra = { 10 | "example": { 11 | "id": 1, 12 | "item": "Example Schema!" 13 | } 14 | } 15 | 16 | 17 | class TodoItem(BaseModel): 18 | item: str 19 | 20 | class Config: 21 | schema_extra = { 22 | "example": { 23 | "item": "Read the next chapter of the book" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ch08/planner/models/users.py: -------------------------------------------------------------------------------- 1 | from beanie import Document 2 | 3 | from pydantic import BaseModel, EmailStr 4 | 5 | 6 | class User(Document): 7 | email: EmailStr 8 | password: str 9 | 10 | class Settings: 11 | name = "users" 12 | 13 | class Config: 14 | schema_extra = { 15 | "example": { 16 | "email": "fastapi@packt.com", 17 | "password": "strong!!!" 18 | } 19 | } 20 | 21 | 22 | class TokenResponse(BaseModel): 23 | access_token: str 24 | token_type: str 25 | -------------------------------------------------------------------------------- /ch09/planner/models/users.py: -------------------------------------------------------------------------------- 1 | from beanie import Document 2 | 3 | from pydantic import BaseModel, EmailStr 4 | 5 | 6 | class User(Document): 7 | email: EmailStr 8 | password: str 9 | 10 | class Settings: 11 | name = "users" 12 | 13 | class Config: 14 | schema_extra = { 15 | "example": { 16 | "email": "fastapi@packt.com", 17 | "password": "strong!!!" 18 | } 19 | } 20 | 21 | 22 | class TokenResponse(BaseModel): 23 | access_token: str 24 | token_type: str 25 | -------------------------------------------------------------------------------- /ch05/planner/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from fastapi.responses import RedirectResponse 3 | 4 | from routes.users import user_router 5 | from routes.events import event_router 6 | 7 | import uvicorn 8 | 9 | app = FastAPI() 10 | 11 | # 라우트 등록 12 | 13 | app.include_router(user_router, prefix="/user") 14 | app.include_router(event_router, prefix="/event") 15 | 16 | 17 | @app.get("/") 18 | async def home(): 19 | return RedirectResponse(url="/event/") 20 | 21 | if __name__ == '__main__': 22 | uvicorn.run("main:app", host="127.0.0.1", port=8000, reload=True) -------------------------------------------------------------------------------- /ch07/planner/auth/authenticate.py: -------------------------------------------------------------------------------- 1 | from auth.jwt_handler import verify_access_token 2 | from fastapi import Depends, HTTPException, status 3 | from fastapi.security import OAuth2PasswordBearer 4 | 5 | oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/user/signin") 6 | 7 | 8 | async def authenticate(token: str = Depends(oauth2_scheme)) -> str: 9 | if not token: 10 | raise HTTPException( 11 | status_code=status.HTTP_403_FORBIDDEN, 12 | detail="Sign in for access" 13 | ) 14 | 15 | decoded_token = verify_access_token(token) 16 | return decoded_token["user"] 17 | -------------------------------------------------------------------------------- /ch08/planner/auth/authenticate.py: -------------------------------------------------------------------------------- 1 | from auth.jwt_handler import verify_access_token 2 | from fastapi import Depends, HTTPException, status 3 | from fastapi.security import OAuth2PasswordBearer 4 | 5 | oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/user/signin") 6 | 7 | 8 | async def authenticate(token: str = Depends(oauth2_scheme)) -> str: 9 | if not token: 10 | raise HTTPException( 11 | status_code=status.HTTP_403_FORBIDDEN, 12 | detail="Sign in for access" 13 | ) 14 | 15 | decoded_token = await verify_access_token(token) 16 | return decoded_token["user"] 17 | -------------------------------------------------------------------------------- /ch09/planner/auth/authenticate.py: -------------------------------------------------------------------------------- 1 | from auth.jwt_handler import verify_access_token 2 | from fastapi import Depends, HTTPException, status 3 | from fastapi.security import OAuth2PasswordBearer 4 | 5 | oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/user/signin") 6 | 7 | 8 | async def authenticate(token: str = Depends(oauth2_scheme)) -> str: 9 | if not token: 10 | raise HTTPException( 11 | status_code=status.HTTP_403_FORBIDDEN, 12 | detail="Sign in for access" 13 | ) 14 | 15 | decoded_token = await verify_access_token(token) 16 | return decoded_token["user"] 17 | -------------------------------------------------------------------------------- /ch08/planner/tests/test_arthmetic_operations.py: -------------------------------------------------------------------------------- 1 | def add(a: int, b: int) -> int: 2 | return a + b 3 | 4 | 5 | def subtract(a: int, b: int) -> int: 6 | return b - a 7 | 8 | 9 | def multiply(a: int, b: int) -> int: 10 | return a * b 11 | 12 | 13 | def divide(a: int, b: int) -> int: 14 | return b // a 15 | 16 | 17 | def test_add() -> None: 18 | assert add(1, 1) == 2 19 | 20 | 21 | def test_subtract() -> None: 22 | assert subtract(2, 5) == 3 23 | 24 | 25 | def test_multiply() -> None: 26 | assert multiply(10, 10) == 100 27 | 28 | 29 | def test_divide() -> None: 30 | assert divide(25, 100) == 4 31 | -------------------------------------------------------------------------------- /ch09/planner/tests/test_arthmetic_operations.py: -------------------------------------------------------------------------------- 1 | def add(a: int, b: int) -> int: 2 | return a + b 3 | 4 | 5 | def subtract(a: int, b: int) -> int: 6 | return b - a 7 | 8 | 9 | def multiply(a: int, b: int) -> int: 10 | return a * b 11 | 12 | 13 | def divide(a: int, b: int) -> int: 14 | return b // a 15 | 16 | 17 | def test_add() -> None: 18 | assert add(1, 1) == 2 19 | 20 | 21 | def test_subtract() -> None: 22 | assert subtract(2, 5) == 3 23 | 24 | 25 | def test_multiply() -> None: 26 | assert multiply(10, 10) == 100 27 | 28 | 29 | def test_divide() -> None: 30 | assert divide(25, 100) == 4 31 | -------------------------------------------------------------------------------- /ch08/planner/tests/test_fixture.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | # Fixture is defined. 4 | from models.events import EventUpdate 5 | 6 | 7 | @pytest.fixture 8 | def event() -> EventUpdate: 9 | return EventUpdate( 10 | title="FastAPI Book Launch", 11 | image="https://packt.com/fastapi.png", 12 | description="We will be discussing the contents of the FastAPI book in this event.Ensure to come with your own copy to win gifts!", 13 | tags=["python", "fastapi", "book", "launch"], 14 | location="Google Meet" 15 | ) 16 | 17 | 18 | def test_event_name(event: EventUpdate) -> None: 19 | assert event.title == "FastAPI Book Launch" 20 | -------------------------------------------------------------------------------- /ch09/planner/tests/test_fixture.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | # Fixture is defined. 4 | from models.events import EventUpdate 5 | 6 | 7 | @pytest.fixture 8 | def event() -> EventUpdate: 9 | return EventUpdate( 10 | title="FastAPI Book Launch", 11 | image="https://packt.com/fastapi.png", 12 | description="We will be discussing the contents of the FastAPI book in this event.Ensure to come with your own copy to win gifts!", 13 | tags=["python", "fastapi", "book", "launch"], 14 | location="Google Meet" 15 | ) 16 | 17 | 18 | def test_event_name(event: EventUpdate) -> None: 19 | assert event.title == "FastAPI Book Launch" 20 | -------------------------------------------------------------------------------- /ch05/planner/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.5.0 2 | asgiref==3.5.0 3 | bcrypt==3.2.0 4 | beanie==1.10.4 5 | cffi==1.15.0 6 | click==8.0.4 7 | dnspython==2.2.0 8 | email-validator==1.1.3 9 | fastapi==0.74.1 10 | h11==0.13.0 11 | idna==3.3 12 | Jinja2==3.0.3 13 | MarkupSafe==2.1.0 14 | motor==2.5.1 15 | multidict==6.0.2 16 | passlib==1.7.4 17 | pycparser==2.21 18 | pydantic==1.9.0 19 | PyJWT==2.3.0 20 | pymongo==3.12.3 21 | python-dotenv==0.20.0 22 | python-multipart==0.0.5 23 | six==1.16.0 24 | sniffio==1.2.0 25 | SQLAlchemy==1.4.32 26 | sqlalchemy2-stubs==0.0.2a20 27 | sqlmodel==0.0.6 28 | starlette==0.17.1 29 | toml==0.10.2 30 | typing_extensions==4.1.1 31 | uvicorn==0.17.5 32 | yarl==1.7.2 33 | -------------------------------------------------------------------------------- /ch06/planner/models/users.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, List 2 | from beanie import Document, Link 3 | from pydantic import BaseModel, EmailStr 4 | from models.events import Event 5 | 6 | class User(Document): 7 | email: EmailStr 8 | password: str 9 | events: Optional[List[Event]] 10 | 11 | class Settings: 12 | name = "users" 13 | 14 | class Config: 15 | schema_extra = { 16 | "example": { 17 | "email": "fastapi@packt.com", 18 | "username": "strong!!!", 19 | "events": [], 20 | } 21 | } 22 | 23 | class UserSignIn(Document): 24 | email: EmailStr 25 | password: str 26 | -------------------------------------------------------------------------------- /ch06/planner/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.5.0 2 | asgiref==3.5.0 3 | bcrypt==3.2.0 4 | beanie==1.10.4 5 | cffi==1.15.0 6 | click==8.0.4 7 | dnspython==2.2.0 8 | email-validator==1.1.3 9 | fastapi==0.74.1 10 | h11==0.13.0 11 | idna==3.3 12 | Jinja2==3.0.3 13 | MarkupSafe==2.1.0 14 | motor==2.5.1 15 | multidict==6.0.2 16 | passlib==1.7.4 17 | pycparser==2.21 18 | pydantic==1.9.0 19 | PyJWT==2.3.0 20 | pymongo==3.12.3 21 | python-dotenv==0.20.0 22 | python-multipart==0.0.5 23 | six==1.16.0 24 | sniffio==1.2.0 25 | SQLAlchemy==1.4.32 26 | sqlalchemy2-stubs==0.0.2a20 27 | sqlmodel==0.0.6 28 | starlette==0.17.1 29 | toml==0.10.2 30 | typing_extensions==4.1.1 31 | uvicorn==0.17.5 32 | yarl==1.7.2 33 | -------------------------------------------------------------------------------- /ch07/planner/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.5.0 2 | asgiref==3.5.0 3 | bcrypt==3.2.0 4 | beanie==1.10.4 5 | cffi==1.15.0 6 | click==8.0.4 7 | cryptography==36.0.2 8 | dnspython==2.2.0 9 | ecdsa==0.17.0 10 | email-validator==1.1.3 11 | fastapi==0.74.1 12 | h11==0.13.0 13 | idna==3.3 14 | Jinja2==3.0.3 15 | MarkupSafe==2.1.0 16 | motor==2.5.1 17 | multidict==6.0.2 18 | passlib==1.7.4 19 | pyasn1==0.4.8 20 | pycparser==2.21 21 | pydantic==1.9.0 22 | pymongo==3.12.3 23 | python-dotenv==0.20.0 24 | python-jose==3.3.0 25 | python-multipart==0.0.5 26 | rsa==4.8 27 | six==1.16.0 28 | sniffio==1.2.0 29 | SQLAlchemy==1.4.32 30 | sqlalchemy2-stubs==0.0.2a20 31 | sqlmodel==0.0.6 32 | starlette==0.17.1 33 | toml==0.10.2 34 | typing_extensions==4.1.1 35 | uvicorn==0.17.5 36 | yarl==1.7.2 37 | -------------------------------------------------------------------------------- /ch05/planner/models/events.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class Event(BaseModel): 7 | id: int 8 | title: str 9 | image: str 10 | description: str 11 | tags: List[str] 12 | location: str 13 | 14 | class Config: 15 | schema_extra = { 16 | "example": { 17 | "title": "FastAPI Book Launch", 18 | "image": "https://linktomyimage.com/image.png", 19 | "description": "We will be discussing the contents of the FastAPI book in this event.Ensure to come with your own copy to win gifts!", 20 | "tags": ["python", "fastapi", "book", "launch"], 21 | "location": "Google Meet" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ch06/planner/main.py: -------------------------------------------------------------------------------- 1 | import uvicorn 2 | from fastapi import FastAPI 3 | from fastapi.responses import RedirectResponse 4 | 5 | from database.connection import Settings 6 | from routes.events import event_router 7 | from routes.users import user_router 8 | 9 | app = FastAPI() 10 | 11 | settings = Settings() 12 | 13 | # 라우트 등록 14 | 15 | app.include_router(user_router, prefix="/user") 16 | app.include_router(event_router, prefix="/event") 17 | 18 | 19 | @app.on_event("startup") 20 | async def init_db(): 21 | await settings.initialize_database() 22 | 23 | 24 | @app.get("/") 25 | async def home(): 26 | return RedirectResponse(url="/event/") 27 | 28 | 29 | if __name__ == '__main__': 30 | uvicorn.run("main:app", host="127.0.0.1", port=8000, reload=True) 31 | -------------------------------------------------------------------------------- /ch05/planner/models/users.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, EmailStr 2 | from typing import Optional, List 3 | from models.events import Event 4 | 5 | 6 | 7 | class User(BaseModel): 8 | email: EmailStr 9 | password: str 10 | events: Optional[List[Event]] 11 | 12 | 13 | class Config: 14 | schema_extra = { 15 | "example": { 16 | "email": "fastapi@packt.com", 17 | "username": "strong!!!", 18 | "events": [], 19 | } 20 | } 21 | 22 | 23 | 24 | 25 | class UserSignIn(BaseModel): 26 | email: EmailStr 27 | password: str 28 | 29 | class Config: 30 | schema_extra = { 31 | "example": { 32 | "email": "fastapi@packt.com", 33 | "password": "strong!!!", 34 | "events": [], 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ch08/planner/tests/conftest.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | import httpx 4 | import pytest 5 | 6 | from database.connection import Settings 7 | from main import app 8 | from models.events import Event 9 | from models.users import User 10 | 11 | 12 | @pytest.fixture(scope="session") 13 | def event_loop(): 14 | loop = asyncio.get_event_loop() 15 | yield loop 16 | loop.close() 17 | 18 | 19 | async def init_db(): 20 | test_settings = Settings() 21 | test_settings.DATABASE_URL = "mongodb://localhost:27017/testdb" 22 | 23 | await test_settings.initialize_database() 24 | 25 | 26 | @pytest.fixture(scope="session") 27 | async def default_client(): 28 | await init_db() 29 | async with httpx.AsyncClient(app=app, base_url="http://app") as client: 30 | yield client 31 | 32 | # 리소스 정리 33 | await Event.find_all().delete() 34 | await User.find_all().delete() 35 | -------------------------------------------------------------------------------- /ch09/planner/tests/conftest.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | import httpx 4 | import pytest 5 | from database.connection import Settings 6 | from main import app 7 | from models.events import Event 8 | from models.users import User 9 | 10 | 11 | @pytest.fixture(scope="session") 12 | def event_loop(): 13 | loop = asyncio.get_event_loop() 14 | yield loop 15 | loop.close() 16 | 17 | 18 | async def init_db(): 19 | test_settings = Settings() 20 | test_settings.DATABASE_URL = "mongodb://localhost:27017/testdb" 21 | 22 | await test_settings.initialize_database() 23 | 24 | 25 | @pytest.fixture(scope="session") 26 | async def default_client(): 27 | await init_db() 28 | async with httpx.AsyncClient(app=app, base_url="http://app") as client: 29 | yield client 30 | 31 | # Clean up resources 32 | await Event.find_all().delete() 33 | await User.find_all().delete() 34 | -------------------------------------------------------------------------------- /ch07/planner/main.py: -------------------------------------------------------------------------------- 1 | import uvicorn 2 | from fastapi import FastAPI 3 | from fastapi.responses import RedirectResponse 4 | from fastapi.middleware.cors import CORSMiddleware 5 | 6 | from database.connection import Settings 7 | from routes.events import event_router 8 | from routes.users import user_router 9 | 10 | app = FastAPI() 11 | 12 | settings = Settings() 13 | 14 | # 출처 등록 15 | 16 | origins = ["*"] 17 | 18 | app.add_middleware( 19 | CORSMiddleware, 20 | allow_origins=origins, 21 | allow_credentials=True, 22 | allow_methods=["*"], 23 | allow_headers=["*"], 24 | ) 25 | 26 | # 라우트 등록 27 | 28 | app.include_router(user_router, prefix="/user") 29 | app.include_router(event_router, prefix="/event") 30 | 31 | 32 | @app.on_event("startup") 33 | async def init_db(): 34 | await settings.initialize_database() 35 | 36 | 37 | @app.get("/") 38 | async def home(): 39 | return RedirectResponse(url="/event/") 40 | 41 | 42 | if __name__ == '__main__': 43 | uvicorn.run("main:app", host="127.0.0.1", port=8000, reload=True) 44 | -------------------------------------------------------------------------------- /ch03/todos/model.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class Todo(BaseModel): 7 | id: int 8 | item: str 9 | 10 | class Config: 11 | schema_extra = { 12 | "example": { 13 | "id": 1, 14 | "item": "Example schema!" 15 | } 16 | } 17 | 18 | class TodoItem(BaseModel): 19 | item: str 20 | 21 | class Config: 22 | schema_extra = { 23 | "example": { 24 | "item": "Read the next chapter of the book" 25 | } 26 | } 27 | 28 | 29 | class TodoItems(BaseModel): 30 | todos: List[TodoItem] 31 | 32 | class Config: 33 | schema_extra = { 34 | "example": { 35 | "todos": [ 36 | { 37 | "item": "Example schema 1!" 38 | }, 39 | { 40 | "item": "Example schema 2!" 41 | } 42 | ] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ch08/planner/main.py: -------------------------------------------------------------------------------- 1 | import uvicorn 2 | from fastapi import FastAPI 3 | from fastapi.responses import RedirectResponse 4 | from fastapi.middleware.cors import CORSMiddleware 5 | 6 | from database.connection import Settings 7 | from routes.events import event_router 8 | from routes.users import user_router 9 | 10 | app = FastAPI() 11 | 12 | settings = Settings() 13 | 14 | 15 | # 출처 등록 16 | 17 | origins = ["*"] 18 | 19 | app.add_middleware( 20 | CORSMiddleware, 21 | allow_origins=origins, 22 | allow_credentials=True, 23 | allow_methods=["*"], 24 | allow_headers=["*"], 25 | ) 26 | 27 | # 라우트 등록 28 | 29 | app.include_router(user_router, prefix="/user") 30 | app.include_router(event_router, prefix="/event") 31 | 32 | 33 | @app.on_event("startup") 34 | async def init_db(): 35 | await settings.initialize_database() 36 | 37 | 38 | @app.get("/") 39 | async def home(): 40 | return RedirectResponse(url="/event/") 41 | 42 | 43 | if __name__ == '__main__': 44 | uvicorn.run("main:app", host="127.0.0.1", port=8000, reload=True) 45 | -------------------------------------------------------------------------------- /ch09/planner/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from fastapi.middleware.cors import CORSMiddleware 3 | from fastapi.responses import RedirectResponse 4 | from database.connection import Settings 5 | 6 | from routes.users import user_router 7 | from routes.events import event_router 8 | 9 | import uvicorn 10 | 11 | app = FastAPI() 12 | 13 | settings = Settings() 14 | 15 | 16 | # 출처 등록 17 | 18 | origins = ["*"] 19 | 20 | app.add_middleware( 21 | CORSMiddleware, 22 | allow_origins=origins, 23 | allow_credentials=True, 24 | allow_methods=["*"], 25 | allow_headers=["*"], 26 | ) 27 | 28 | 29 | # 라우트 등록 30 | 31 | app.include_router(user_router, prefix="/user") 32 | app.include_router(event_router, prefix="/event") 33 | 34 | 35 | @app.on_event("startup") 36 | async def init_db(): 37 | await settings.initialize_database() 38 | 39 | 40 | @app.get("/") 41 | async def home(): 42 | return RedirectResponse(url="/event/") 43 | 44 | if __name__ == '__main__': 45 | uvicorn.run("main:app", host="127.0.0.1", port=8000, reload=True) -------------------------------------------------------------------------------- /ch04/todos/templates/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 |
4 |
5 | 『[FastAPI를 사용한 파이썬 웹 개발](https://www.hanbit.co.kr/store/books/look.php?p_code=B9703548802)』(한빛미디어, 2023) 예제 코드 저장소입니다.
6 | 이 저장소의 코드는 원서의 저자가 제공하는 코드 중 실행 오류가 발생하거나 오탈자가 있는 부분을 수정한 것입니다.
7 |
8 | 원서의 저자가 제공하는 코드는 [여기](https://github.com/PacktPublishing/Building-Python-Web-APIs-with-FastAPI)에서 확인할 수 있습니다.
9 |
10 |
11 | ## 이 책에 대하여
12 | FastAPI는 파이썬으로 API를 구축할 수 있게 해주는 빠르고 효율적인 웹 프레임워크입니다. 이 책은 FastAPI 프레임워크를 사용한 애플리케이션 구축 방법을 안내합니다. 먼저 책에서 사용하는 기술의 기본 개념을 살펴보고 라우팅 시스템, 응답 모델링, 오류 처리, 템플릿 등 FastAPI 프레임워크의 주요 기능을 설명합니다.
13 |
14 | 여러분은 파이썬과 FastAPI를 사용해서 빠르고 효율적이며 확장 가능한 애플리케이션 구축 방법을 배우게 됩니다. 간단한 ‘Hello World’ 애플리케이션 개발부터 데이터베이스, 인증, 템플릿 등을 사용한 전체적인 API 구축 방법을 다루고 효율성, 가독성, 확장성을 개선하는 애플리케이션 설계 방법을 학습합니다. 또한 애플리케이션을 외부 라이브러리와 연동해서 SQL 또는 NoSQL 데이터베이스에 연결하고, 템플릿을 통합하고, 인증 시스템을 개발하는 방법도 배웁니다. 책의 후반부에서는 테스트 작성, 애플리케이션 컨테이너화 방법을 살펴보고 도커를 사용해 애플리케이션을 배포합니다. 이 모든 내용은 실습과 함께 설명합니다.
15 |
16 | 책을 다 읽고 나면 FastAPI 프레임워크를 사용해서 강력한 웹 API를 구축하고 배포할 수 있습니다.
17 |
18 |
19 | ## 목차
20 | **PART 1. FastAPI 학습하기**
21 | CHAPTER 1. FastAPI 소개
22 | CHAPTER 2. 라우팅
23 | CHAPTER 3. 응답 모델과 오류 처리
24 | CHAPTER 4. 템플릿팅
25 |
26 | **PART 2. FastAPI 애플리케이션 개발하기**
27 | CHAPTER 5. 구조화
28 | CHAPTER 6. 데이터베이스 연결
29 | CHAPTER 7. 보안
30 |
31 | **PART 3. FastAPI 애플리케이션 테스트 및 배포하기**
32 | CHAPTER 8. 테스트
33 | CHAPTER 9. 배포
34 |
--------------------------------------------------------------------------------
/ch07/planner/models/events.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, List
2 |
3 | from beanie import Document
4 | from pydantic import BaseModel
5 |
6 |
7 | class Event(Document):
8 | creator: Optional[str]
9 | title: str
10 | image: str
11 | description: str
12 | tags: List[str]
13 | location: str
14 |
15 | class Config:
16 | schema_extra = {
17 | "example": {
18 | "title": "FastAPI BookLaunch",
19 | "image": "https://linktomyimage.com/image.png",
20 | "description": "We will be discussing the contents of the FastAPI book in this event.Ensure to come with your own copy to win gifts!",
21 | "tags": ["python", "fastapi", "book", "launch"],
22 | "location": "Google Meet"
23 | }
24 | }
25 |
26 | class Collection:
27 | name = "events"
28 |
29 |
30 | class EventUpdate(BaseModel):
31 | title: Optional[str]
32 | image: Optional[str]
33 | description: Optional[str]
34 | tags: Optional[List[str]]
35 | location: Optional[str]
36 |
37 | class Config:
38 | schema_extra = {
39 | "example": {
40 | "title": "FastAPI BookLaunch",
41 | "image": "https://linktomyimage.com/image.png",
42 | "description": "We will be discussing the contents of the FastAPI book in this event.Ensure to come with your own copy to win gifts!",
43 | "tags": ["python", "fastapi", "book", "launch"],
44 | "location": "Google Meet"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ch06/planner/models/events.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, List
2 |
3 | from beanie import Document
4 | from pydantic import BaseModel
5 |
6 |
7 | class Event(Document):
8 | title: str
9 | image: str
10 | description: str
11 | tags: List[str]
12 | location: str
13 |
14 | class Config:
15 | schema_extra = {
16 | "example": {
17 | "title": "FastAPI BookLaunch",
18 | "image": "https://linktomyimage.com/image.png",
19 | "description": "We will be discussing the contents of the FastAPI book in this event.Ensure to come with your own copy to win gifts!",
20 | "tags": ["python", "fastapi", "book", "launch"],
21 | "location": "Google Meet"
22 | }
23 | }
24 |
25 | class Settings:
26 | name = "events"
27 |
28 |
29 | class EventUpdate(BaseModel):
30 | title: Optional[str]
31 | image: Optional[str]
32 | description: Optional[str]
33 | tags: Optional[List[str]]
34 | location: Optional[str]
35 |
36 | class Config:
37 | schema_extra = {
38 | "example": {
39 | "title": "FastAPI BookLaunch",
40 | "image": "https://linktomyimage.com/image.png",
41 | "description": "We will be discussing the contents of the FastAPI book in this event.Ensure to come with your own copy to win gifts!",
42 | "tags": ["python", "fastapi", "book", "launch"],
43 | "location": "Google Meet"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/ch05/planner/routes/events.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from fastapi import APIRouter, Body, HTTPException, status
4 | from models.events import Event
5 |
6 | event_router = APIRouter(
7 | tags=["Events"]
8 | )
9 |
10 | events = []
11 |
12 |
13 | @event_router.get("/", response_model=List[Event])
14 | async def retrieve_all_events() -> List[Event]:
15 | return events
16 |
17 | @event_router.get("/{id}", response_model=Event)
18 | async def retrieve_event(id: int) -> Event:
19 | for event in events:
20 | if event.id == id:
21 | return event
22 | raise HTTPException(
23 | status_code=status.HTTP_404_NOT_FOUND,
24 | detail="Event with supplied ID does not exist"
25 | )
26 |
27 |
28 | @event_router.post("/new")
29 | async def create_event(body: Event = Body(...)) -> dict:
30 | events.append(body)
31 | return {
32 | "message": "Event created successfully"
33 | }
34 |
35 |
36 | @event_router.delete("/{id}")
37 | async def delete_event(id: int) -> dict:
38 | for event in events:
39 | if event.id == id:
40 | events.remove(event)
41 | return {
42 | "message": "Event deleted successfully"
43 | }
44 | raise HTTPException(
45 | status_code=status.HTTP_404_NOT_FOUND,
46 | detail="Event with supplied ID does not exist"
47 | )
48 |
49 | @event_router.delete("/")
50 | async def delete_all_events() -> dict:
51 | events.clear()
52 | return {
53 | "message": "Events deleted successfully"
54 | }
55 |
--------------------------------------------------------------------------------
/ch08/planner/models/events.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, List
2 |
3 | from beanie import Document
4 | from pydantic import BaseModel
5 |
6 |
7 | class Event(Document):
8 | creator: Optional[str]
9 | title: str
10 | image: str
11 | description: str
12 | tags: List[str]
13 | location: str
14 |
15 | class Config:
16 | schema_extra = {
17 | "example": {
18 | "title": "FastAPI Book Launch",
19 | "image": "https://linktomyimage.com/image.png",
20 | "description": "We will be discussing the contents of the FastAPI book in this event.Ensure to come with your own copy to win gifts!",
21 | "tags": ["python", "fastapi", "book", "launch"],
22 | "location": "Google Meet"
23 | }
24 | }
25 |
26 | class Settings:
27 | name = "events"
28 |
29 |
30 | class EventUpdate(BaseModel):
31 | title: Optional[str]
32 | image: Optional[str]
33 | description: Optional[str]
34 | tags: Optional[List[str]]
35 | location: Optional[str]
36 |
37 | class Config:
38 | schema_extra = {
39 | "example": {
40 | "title": "FastAPI BookLaunch",
41 | "image": "https://linktomyimage.com/image.png",
42 | "description": "We will be discussing the contents of the FastAPI book in this event.Ensure to come with your own copy to win gifts!",
43 | "tags": ["python", "fastapi", "book", "launch"],
44 | "location": "Google Meet"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ch09/planner/models/events.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, List
2 |
3 | from beanie import Document
4 | from pydantic import BaseModel
5 |
6 |
7 | class Event(Document):
8 | creator: Optional[str]
9 | title: str
10 | image: str
11 | description: str
12 | tags: List[str]
13 | location: str
14 |
15 | class Config:
16 | schema_extra = {
17 | "example": {
18 | "title": "FastAPI Book Launch",
19 | "image": "https://linktomyimage.com/image.png",
20 | "description": "We will be discussing the contents of the FastAPI book in this event.Ensure to come with your own copy to win gifts!",
21 | "tags": ["python", "fastapi", "book", "launch"],
22 | "location": "Google Meet"
23 | }
24 | }
25 |
26 | class Settings:
27 | name = "events"
28 |
29 |
30 | class EventUpdate(BaseModel):
31 | title: Optional[str]
32 | image: Optional[str]
33 | description: Optional[str]
34 | tags: Optional[List[str]]
35 | location: Optional[str]
36 |
37 | class Config:
38 | schema_extra = {
39 | "example": {
40 | "title": "FastAPI BookLaunch",
41 | "image": "https://linktomyimage.com/image.png",
42 | "description": "We will be discussing the contents of the FastAPI book in this event.Ensure to come with your own copy to win gifts!",
43 | "tags": ["python", "fastapi", "book", "launch"],
44 | "location": "Google Meet"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ch08/planner/auth/jwt_handler.py:
--------------------------------------------------------------------------------
1 | import time
2 | from datetime import datetime
3 |
4 | from database.connection import Settings
5 | from fastapi import HTTPException, status
6 | from jose import jwt, JWTError
7 | from models.users import User
8 |
9 | settings = Settings()
10 |
11 |
12 | def create_access_token(user: str) -> str:
13 | payload = {
14 | "user": user,
15 | "expires": time.time() + 3600
16 | }
17 |
18 | token = jwt.encode(payload, settings.SECRET_KEY, algorithm="HS256")
19 | return token
20 |
21 |
22 | async def verify_access_token(token: str) -> dict:
23 | try:
24 | data = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
25 |
26 | expire = data.get("expires")
27 |
28 | if expire is None:
29 | raise HTTPException(
30 | status_code=status.HTTP_400_BAD_REQUEST,
31 | detail="No access token supplied"
32 | )
33 | if datetime.utcnow() > datetime.utcfromtimestamp(expire):
34 | raise HTTPException(
35 | status_code=status.HTTP_403_FORBIDDEN,
36 | detail="Token expired!"
37 | )
38 | user_exist = await User.find_one(User.email == data["user"])
39 | if not user_exist:
40 | raise HTTPException(
41 | status_code=status.HTTP_400_BAD_REQUEST,
42 | detail="Invalid token"
43 | )
44 |
45 | return data
46 |
47 | except JWTError:
48 | raise HTTPException(
49 | status_code=status.HTTP_400_BAD_REQUEST,
50 | detail="Invalid token"
51 | )
52 |
--------------------------------------------------------------------------------
/ch09/planner/auth/jwt_handler.py:
--------------------------------------------------------------------------------
1 | import time
2 | from datetime import datetime
3 |
4 | from database.connection import Settings
5 | from fastapi import HTTPException, status
6 | from jose import jwt, JWTError
7 | from models.users import User
8 |
9 | settings = Settings()
10 |
11 |
12 | def create_access_token(user: str) -> str:
13 | payload = {
14 | "user": user,
15 | "expires": time.time() + 3600
16 | }
17 |
18 | token = jwt.encode(payload, settings.SECRET_KEY, algorithm="HS256")
19 | return token
20 |
21 |
22 | async def verify_access_token(token: str) -> dict:
23 | try:
24 | data = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
25 |
26 | expire = data.get("expires")
27 |
28 | if expire is None:
29 | raise HTTPException(
30 | status_code=status.HTTP_400_BAD_REQUEST,
31 | detail="No access token supplied"
32 | )
33 | if datetime.utcnow() > datetime.utcfromtimestamp(expire):
34 | raise HTTPException(
35 | status_code=status.HTTP_403_FORBIDDEN,
36 | detail="Token expired!"
37 | )
38 | user_exist = await User.find_one(User.email == data["user"])
39 | if not user_exist:
40 | raise HTTPException(
41 | status_code=status.HTTP_400_BAD_REQUEST,
42 | detail="Invalid token"
43 | )
44 |
45 | return data
46 |
47 | except JWTError:
48 | raise HTTPException(
49 | status_code=status.HTTP_400_BAD_REQUEST,
50 | detail="Invalid token"
51 | )
52 |
--------------------------------------------------------------------------------
/ch04/todos/templates/todo.html:
--------------------------------------------------------------------------------
1 | {% extends "home.html" %}
2 |
3 | {% block todo_container %}
4 | 26 | 27 | Item: {{ todo.item }} 28 | 29 |
30 |63 | « prev 64 | ^ index 65 | » next 66 | 67 | coverage.py v7.1.0, 68 | created at 2023-02-05 19:00 +0800 69 |
70 | 80 |63 | « prev 64 | ^ index 65 | » next 66 | 67 | coverage.py v7.1.0, 68 | created at 2023-02-05 19:00 +0800 69 |
70 | 80 |63 | « prev 64 | ^ index 65 | » next 66 | 67 | coverage.py v7.1.0, 68 | created at 2023-02-05 19:00 +0800 69 |
70 | 80 |63 | « prev 64 | ^ index 65 | » next 66 | 67 | coverage.py v7.1.0, 68 | created at 2023-02-05 19:00 +0800 69 |
70 | 80 |63 | « prev 64 | ^ index 65 | » next 66 | 67 | coverage.py v7.1.0, 68 | created at 2023-02-05 19:00 +0800 69 |
70 | 80 |1from passlib.context import CryptContext
84 | 85 |3pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
86 | 87 | 88 |6class HashPassword:
89 |7 def create_hash(self, password: str) -> str:
90 |8 return pwd_context.hash(password)
91 | 92 |10 def verify_hash(self, plain_password: str, hashed_password: str) -> bool:
93 |11 return pwd_context.verify(plain_password, hashed_password)
94 |63 | « prev 64 | ^ index 65 | » next 66 | 67 | coverage.py v7.1.0, 68 | created at 2023-02-05 19:00 +0800 69 |
70 | 80 |1from auth.jwt_handler import verify_access_token
84 |2from fastapi import Depends, HTTPException, status
85 |3from fastapi.security import OAuth2PasswordBearer
86 | 87 |5oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/user/signin")
88 | 89 | 90 |8async def authenticate(token: str = Depends(oauth2_scheme)) -> str:
91 |9 if not token:
92 |10 raise HTTPException(
93 |11 status_code=status.HTTP_403_FORBIDDEN,
94 |12 detail="Sign in for access"
95 |13 )
96 | 97 |15 decoded_token = await verify_access_token(token)
98 |16 return decoded_token["user"]
99 |63 | « prev 64 | ^ index 65 | » next 66 | 67 | coverage.py v7.1.0, 68 | created at 2023-02-05 19:00 +0800 69 |
70 | 80 |1import pytest
84 | 85 |3# Fixture is defined.
86 |4from models.events import EventUpdate
87 | 88 | 89 |7@pytest.fixture
90 |8def event() -> EventUpdate:
91 |9 return EventUpdate(
92 |10 title="FastAPI Book Launch",
93 |11 image="https://packt.com/fastapi.png",
94 |12 description="We will be discussing the contents of the FastAPI book in this event.Ensure to come with your own copy to win gifts!",
95 |13 tags=["python", "fastapi", "book", "launch"],
96 |14 location="Google Meet"
97 |15 )
98 | 99 | 100 |18def test_event_name(event: EventUpdate) -> None:
101 |19 assert event.title == "FastAPI Book Launch"
102 |63 | « prev 64 | ^ index 65 | » next 66 | 67 | coverage.py v7.1.0, 68 | created at 2023-02-05 19:00 +0800 69 |
70 | 80 |1from beanie import Document
84 | 85 |3from pydantic import BaseModel, EmailStr
86 | 87 | 88 |6class User(Document):
89 |7 email: EmailStr
90 |8 password: str
91 | 92 |10 class Settings:
93 |11 name = "users"
94 | 95 |13 class Config:
96 |14 schema_extra = {
97 |15 "example": {
98 |16 "email": "fastapi@packt.com",
99 |17 "password": "strong!!!"
100 |18 }
101 |19 }
102 | 103 | 104 |22class TokenResponse(BaseModel):
105 |23 access_token: str
106 |24 token_type: str
107 |47 | coverage.py v7.1.0, 48 | created at 2023-02-05 19:00 +0800 49 |
50 || Module | 57 |statements | 58 |missing | 59 |excluded | 60 |coverage | 61 |
|---|---|---|---|---|
| auth\__init__.py | 66 |0 | 67 |0 | 68 |0 | 69 |100% | 70 |
| auth\authenticate.py | 73 |9 | 74 |1 | 75 |0 | 76 |89% | 77 |
| auth\hash_password.py | 80 |7 | 81 |0 | 82 |0 | 83 |100% | 84 |
| auth\jwt_handler.py | 87 |25 | 88 |5 | 89 |0 | 90 |80% | 91 |
| database\__init__.py | 94 |0 | 95 |0 | 96 |0 | 97 |100% | 98 |
| database\connection.py | 101 |44 | 102 |2 | 103 |0 | 104 |95% | 105 |
| main.py | 108 |21 | 109 |3 | 110 |0 | 111 |86% | 112 |
| models\__init__.py | 115 |0 | 116 |0 | 117 |0 | 118 |100% | 119 |
| models\events.py | 122 |22 | 123 |0 | 124 |0 | 125 |100% | 126 |
| models\users.py | 129 |12 | 130 |0 | 131 |0 | 132 |100% | 133 |
| routes\__init__.py | 136 |0 | 137 |0 | 138 |0 | 139 |100% | 140 |
| routes\events.py | 143 |41 | 144 |4 | 145 |0 | 146 |90% | 147 |
| routes\users.py | 150 |27 | 151 |3 | 152 |0 | 153 |89% | 154 |
| tests\conftest.py | 157 |23 | 158 |0 | 159 |0 | 160 |100% | 161 |
| tests\test_arthmetic_operations.py | 164 |16 | 165 |0 | 166 |0 | 167 |100% | 168 |
| tests\test_fixture.py | 171 |7 | 172 |0 | 173 |0 | 174 |100% | 175 |
| tests\test_login.py | 178 |17 | 179 |0 | 180 |0 | 181 |100% | 182 |
| tests\test_routes.py | 185 |59 | 186 |0 | 187 |0 | 188 |100% | 189 |
| Total | 194 |330 | 195 |18 | 196 |0 | 197 |95% | 198 |
202 | No items found using the specified filter. 203 |
204 |63 | « prev 64 | ^ index 65 | » next 66 | 67 | coverage.py v7.1.0, 68 | created at 2023-02-05 19:00 +0800 69 |
70 | 80 |1def add(a: int, b: int) -> int:
84 |2 return a + b
85 | 86 | 87 |5def subtract(a: int, b: int) -> int:
88 |6 return b - a
89 | 90 | 91 |9def multiply(a: int, b: int) -> int:
92 |10 return a * b
93 | 94 | 95 |13def divide(a: int, b: int) -> int:
96 |14 return b // a
97 | 98 | 99 |17def test_add() -> None:
100 |18 assert add(1, 1) == 2
101 | 102 | 103 |21def test_subtract() -> None:
104 |22 assert subtract(2, 5) == 3
105 | 106 | 107 |25def test_multiply() -> None:
108 |26 assert multiply(10, 10) == 100
109 | 110 | 111 |29def test_divide() -> None:
112 |30 assert divide(25, 100) == 4
113 |63 | « prev 64 | ^ index 65 | » next 66 | 67 | coverage.py v7.1.0, 68 | created at 2023-02-05 19:00 +0800 69 |
70 | 80 |1import asyncio
84 | 85 |3import httpx
86 |4import pytest
87 | 88 |6from database.connection import Settings
89 |7from main import app
90 |8from models.events import Event
91 |9from models.users import User
92 | 93 | 94 |12@pytest.fixture(scope="session")
95 |13def event_loop():
96 |14 loop = asyncio.get_event_loop()
97 |15 yield loop
98 |16 loop.close()
99 | 100 | 101 |19async def init_db():
102 |20 test_settings = Settings()
103 |21 test_settings.DATABASE_URL = "mongodb://localhost:27017/testdb"
104 | 105 |23 await test_settings.initialize_database()
106 | 107 | 108 |26@pytest.fixture(scope="session")
109 |27async def default_client():
110 |28 await init_db()
111 |29 async with httpx.AsyncClient(app=app, base_url="http://app") as client:
112 |30 yield client
113 | 114 |32 # 리소스 정리
115 |33 await Event.find_all().delete()
116 |34 await User.find_all().delete()
117 |