From 72281e5545f91bd22c71198f9b30637d729b6552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20C=C3=A1rdenas?= Date: Thu, 29 Aug 2024 18:55:06 -0500 Subject: [PATCH] feat: #52 update models - re-design the models to adapt new workflow --- .github/workflows/python-app.yml | 5 +- .pre-commit-config.yaml | 15 +++++ app/api/endpoints/courses.py | 26 -------- app/api/endpoints/user.py | 16 ++--- app/api/v_1/endpoints.py | 45 ------------- app/database/models.py | 92 ++++++++++++++------------- app/database/session.py | 4 +- app/repositories/course_repository.py | 13 ---- app/schemas/course.py | 17 ----- app/schemas/user.py | 4 ++ main.py | 5 +- requirements.txt | 8 +++ scripts/__init__.py | 0 scripts/run_black.sh | 15 +++++ scripts/run_pylint.sh | 15 +++++ 15 files changed, 115 insertions(+), 165 deletions(-) create mode 100644 .pre-commit-config.yaml delete mode 100644 app/api/endpoints/courses.py delete mode 100644 app/api/v_1/endpoints.py delete mode 100644 app/repositories/course_repository.py delete mode 100644 app/schemas/course.py delete mode 100644 scripts/__init__.py create mode 100755 scripts/run_black.sh create mode 100755 scripts/run_pylint.sh diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 1ab94b1..88fd663 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -26,8 +26,11 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install flake8 pytest + pip install flake8 pytest black if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + -name: Format with black + run: | + black . - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..e4b9a49 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,15 @@ +repos: + - repo: local + hooks: + - id: run-black + name: Run Black + entry: ./scripts/run_black.sh + language: system + pass_filenames: false + + - id: run-pylint + name: Run Pylint + entry: ./scripts/run_pylint.sh + language: system + pass_filenames: false + diff --git a/app/api/endpoints/courses.py b/app/api/endpoints/courses.py deleted file mode 100644 index 80a186a..0000000 --- a/app/api/endpoints/courses.py +++ /dev/null @@ -1,26 +0,0 @@ -# app/api/endpoints/courses.py - -from fastapi import ( - APIRouter, - Depends, -# HTTPException, -) -from sqlalchemy.orm import Session -from app.database.session import get_db -from app.schemas.course import ( - CourseCreate, -# CourseUpdate, - CourseInDBBase, -) -from app.repositories.course_repository import ( - create_course, -) - -router = APIRouter() - -@router.post("/courses/", response_model=CourseInDBBase) -def create_course_endpoint( - course: CourseCreate, - db: Session = Depends(get_db) -) -> CourseInDBBase: - return create_course(db, course) diff --git a/app/api/endpoints/user.py b/app/api/endpoints/user.py index f011c3f..39ea660 100644 --- a/app/api/endpoints/user.py +++ b/app/api/endpoints/user.py @@ -25,8 +25,7 @@ @router.post("/users/", response_model=UserInDBBase) def create_user_endpoint( - user: UserCreate, - db: Session = Depends(get_db) + user: UserCreate, db: Session = Depends(get_db) ) -> UserInDBBase: return create_user(db, user) @@ -41,18 +40,14 @@ def read_user(user_id: int, db: Session = Depends(get_db)) -> UserInDBBase: @router.get("/users/", response_model=list[UserInDBBase]) def read_users( - skip: int = 0, - limit: int = 10, - db: Session = Depends(get_db) + skip: int = 0, limit: int = 10, db: Session = Depends(get_db) ) -> list[UserInDBBase]: return get_users(db, skip, limit) @router.put("/users/{user_id}", response_model=UserInDBBase) def update_user_endpoint( - user_id: int, - user: UserUpdate, - db: Session = Depends(get_db) + user_id: int, user: UserUpdate, db: Session = Depends(get_db) ) -> UserInDBBase: db_user = get_user(db, user_id) if db_user is None: @@ -61,10 +56,7 @@ def update_user_endpoint( @router.delete("/users/{user_id}", response_model=UserInDBBase) -def delete_user_endpoint( - user_id: int, - db: Session = Depends(get_db) -) -> UserInDBBase: +def delete_user_endpoint(user_id: int, db: Session = Depends(get_db)) -> UserInDBBase: user = delete_user(db, user_id) if user is None: raise HTTPException(status_code=404, detail="User not found") diff --git a/app/api/v_1/endpoints.py b/app/api/v_1/endpoints.py deleted file mode 100644 index 8f5b532..0000000 --- a/app/api/v_1/endpoints.py +++ /dev/null @@ -1,45 +0,0 @@ -# app/api/v1/endpoints.py - -from fastapi import ( - APIRouter, - Depends, -) -from sqlalchemy.orm import Session -from app.database.models import ( - User, - Course, - Topic, -) -from app.database.session import get_db - -router = APIRouter() - - -@router.get("/users/", response_model=None) -def read_users( - skip: int = 0, - limit: int = 10, - db: Session = Depends(get_db) -) -> list[User]: - users = db.query(User).offset(skip).limit(limit).all() - return users - - -@router.get("/courses/", response_model=None) -def read_courses( - skip: int = 0, - limit: int = 10, - db: Session = Depends(get_db) -) -> list[Course]: - courses = db.query(Course).offset(skip).limit(limit).all() - return courses - - -@router.get("/topics/", response_model=None) -def read_topics( - skip: int = 0, - limit: int = 10, - db: Session = Depends(get_db) -) -> list[Topic]: - topics = db.query(Topic).offset(skip).limit(limit).all() - return topics diff --git a/app/database/models.py b/app/database/models.py index acd58c3..9325142 100644 --- a/app/database/models.py +++ b/app/database/models.py @@ -1,16 +1,20 @@ # app/database/models.py +from enum import Enum from sqlalchemy import ( Column, Integer, String, ForeignKey, - Text, ) from sqlalchemy.orm import relationship from app.database.session import Base +class ActivityType(Enum): + question = "question" + + class User(Base): __tablename__ = "users" @@ -21,68 +25,66 @@ class User(Base): created_at = Column(String) updated_at = Column(String) - courses = relationship("Course", back_populates="creator") - topics = relationship("Topic", back_populates="created_by") study_sessions = relationship("StudySession", back_populates="user") + activities = relationship("Activity", back_populates="user") + questions = relationship("Question", back_populates="user") + answers = relationship("Answer", back_populates="user") -class Course(Base): - __tablename__ = "courses" +class StudySession(Base): + __tablename__ = "study_sessions" id: Column = Column(Integer, primary_key=True, index=True) - title: Column = Column(String, index=True) - description: Column = Column(Text) - creator_id: Column = Column(Integer, ForeignKey("users.id")) - created_at = Column(String) - updated_at = Column(String) + user_id: Column = Column(Integer, ForeignKey("users.id")) + start_time: Column = Column(String) + end_time: Column = Column(String) - creator = relationship("User", back_populates="courses") - topics = relationship("Topic", back_populates="course") + user = relationship("User", back_populates="study_sessions") + activities = relationship("Activity", back_populates="study_session") -class Topic(Base): - __tablename__ = "topics" +class Activity(Base): + __tablename__ = "activities" id: Column = Column(Integer, primary_key=True, index=True) - title: Column = Column(String, index=True) - description: Column = Column(Text) - course_id: Column = Column(Integer, ForeignKey("courses.id"), nullable=True) - creator_id: Column = Column(Integer, ForeignKey("users.id")) - created_at: Column = Column(String) - updated_at: Column = Column(String) + user_id: Column = Column(Integer, ForeignKey("users.id")) + study_session_id: Column = Column(Integer, ForeignKey("study_sessions.id")) + type: Column = Column(Enum(ActivityType), nullable=False) + activity: Column = Column(String) + created_at = Column(String) + + user = relationship("User", back_populates="activities") + study_session = relationship("StudySession", back_populates="activities") - course = relationship("Course", back_populates="topics") - created_by = relationship("User", back_populates="topics") - resources = relationship("Resource", back_populates="topic") - study_sessions = relationship("StudySession", back_populates="topic") + question = relationship("Question", back_populates="activity", uselist=False) -class Resource(Base): - __tablename__ = "resources" +class Question(Base): + __tablename__ = "questions" id: Column = Column(Integer, primary_key=True, index=True) - title: Column = Column(String, index=True) - description: Column = Column(Text) - type_of: Column = Column(String) - url: Column = Column(String) - topic_id: Column = Column(Integer, ForeignKey("topics.id")) - creator_id: Column = Column(Integer, ForeignKey("users.id")) - created_at: Column = Column(String) - updated_at: Column = Column(String) + user_id: Column = Column(Integer, ForeignKey("users.id")) + activity_id: Column = Column(Integer, ForeignKey("activities.id")) + question: Column = Column(String) - topic = relationship("Topic", back_populates="resources") - creator = relationship("User") + user = relationship("User", back_populates="questions") + answers = relationship("Answer", back_populates="question") + activity = relationship("Activity", back_populates="question") -class StudySession(Base): - __tablename__ = "study_sessions" +class Answer(Base): + __tablename__ = "answers" id: Column = Column(Integer, primary_key=True, index=True) user_id: Column = Column(Integer, ForeignKey("users.id")) - topic_id: Column = Column(Integer, ForeignKey("topics.id")) - start_time: Column = Column(String) - end_time: Column = Column(String) - technique: Column = Column(String) - - user = relationship("User", back_populates="study_sessions") - topic = relationship("Topic", back_populates="study_sessions") + question_id: Column = Column(Integer, ForeignKey("questions.id")) + answer: Column = Column(String) + + user = relationship("User", back_populates="answers") + question = relationship("Question", back_populates="answers") + parent_answer = relationship( + "Answer", remote_side=[id], back_populates="child_answers" + ) + child_answers = relationship( + "Answer", back_populates="parent_answer", cascade="all, delete-orphan" + ) diff --git a/app/database/session.py b/app/database/session.py index 6c1b1cd..87199ef 100644 --- a/app/database/session.py +++ b/app/database/session.py @@ -20,9 +20,7 @@ ) SessionLocal: sessionmaker = sessionmaker( - autocommit=False, - autoflush=False, - bind=engine + autocommit=False, autoflush=False, bind=engine ) Base = declarative_base() diff --git a/app/repositories/course_repository.py b/app/repositories/course_repository.py deleted file mode 100644 index 49cb4df..0000000 --- a/app/repositories/course_repository.py +++ /dev/null @@ -1,13 +0,0 @@ -# app/repositories/course_repository.py - -from sqlalchemy.orm import Session -from app.database.models import Course -from app.schemas.course import CourseCreate - - -def create_course(db: Session, course: CourseCreate) -> Course: - db_course = Course(**course.model_dump()) - db.add(db_course) - db.commit() - db.refresh(db_course) - return db_course diff --git a/app/schemas/course.py b/app/schemas/course.py deleted file mode 100644 index 0d9d5f7..0000000 --- a/app/schemas/course.py +++ /dev/null @@ -1,17 +0,0 @@ -from pydantic import BaseModel - -class CourseBase(BaseModel): - title: str - description: str - -class CourseCreate(CourseBase): - pass - -class CourseUpdate(CourseBase): - pass - -class CourseInDBBase(CourseBase): - id: int - - class Config: - orm_mode = True diff --git a/app/schemas/user.py b/app/schemas/user.py index 1ef3349..3b178e4 100644 --- a/app/schemas/user.py +++ b/app/schemas/user.py @@ -2,17 +2,21 @@ from pydantic import BaseModel + class UserBase(BaseModel): username: str email: str role: str + class UserCreate(UserBase): pass + class UserUpdate(UserBase): pass + class UserInDBBase(UserBase): id: int diff --git a/main.py b/main.py index 02d52cb..7df589f 100644 --- a/main.py +++ b/main.py @@ -7,7 +7,6 @@ import uvicorn from app.api.endpoints import ( user, - courses, ) from app.database.session import ( Base, @@ -18,7 +17,7 @@ Base.metadata.create_all(bind=engine) app.include_router(user.router) -app.include_router(courses.router) + def get_session(): db = Session(bind=engine) @@ -33,7 +32,7 @@ def read_root(): return {"Hello": "World"} -def main() -> None: +def main() -> None: uvicorn.run(app, host="0.0.0.0", port=8000) diff --git a/requirements.txt b/requirements.txt index 9b576b9..ee5194a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,12 +7,14 @@ astroid==3.1.0 async-timeout==4.0.3 attrs==23.2.0 beautifulsoup4==4.12.3 +black==24.8.0 Brotli==1.1.0 bs4==0.0.2 cachetools==5.3.3 cairocffi==1.7.0 certifi==2024.2.2 cffi==1.16.0 +cfgv==3.4.0 charset-normalizer==3.3.2 click==8.1.7 cssselect2==0.7.0 @@ -20,6 +22,7 @@ dataclasses-json==0.6.4 defusedxml==0.7.1 dill==0.3.8 discord.py==2.3.2 +distlib==0.3.8 distro==1.9.0 dnspython==2.6.1 email_validator==2.2.0 @@ -48,6 +51,7 @@ httplib2==0.22.0 httptools==0.6.1 httpx==0.27.0 huggingface-hub==0.22.2 +identify==2.6.0 idna==3.6 iniconfig==2.0.0 isort==5.13.2 @@ -69,12 +73,15 @@ mccabe==0.7.0 mdurl==0.1.2 multidict==6.0.5 mypy-extensions==1.0.0 +nodeenv==1.9.1 numpy==1.26.4 orjson==3.10.1 packaging==23.2 +pathspec==0.12.1 pillow==10.3.0 platformdirs==4.2.1 pluggy==1.4.0 +pre-commit==3.8.0 proto-plus==1.23.0 protobuf==4.25.3 pyasn1==0.6.0 @@ -115,6 +122,7 @@ uritemplate==4.1.1 urllib3==2.2.1 uvicorn==0.30.5 uvloop==0.19.0 +virtualenv==20.26.3 watchfiles==0.22.0 webencodings==0.5.1 websockets==12.0 diff --git a/scripts/__init__.py b/scripts/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/scripts/run_black.sh b/scripts/run_black.sh new file mode 100755 index 0000000..66daabc --- /dev/null +++ b/scripts/run_black.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# Set up Python environment (assuming Python 3.10 is already installed) +python_version="3.10" + +# Optionally create and activate a virtual environment +# python -m venv venv +# source venv/bin/activate + +# Upgrade pip and install dependencies +python -m pip install --upgrade pip +pip install black + +# Run black +black $(git ls-files '*.py') diff --git a/scripts/run_pylint.sh b/scripts/run_pylint.sh new file mode 100755 index 0000000..d935a42 --- /dev/null +++ b/scripts/run_pylint.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# Set up Python environment (assuming Python 3.10 is already installed) +python_version="3.10" + +# Optionally create and activate a virtual environment +# python -m venv venv +# source venv/bin/activate + +# Upgrade pip and install dependencies +python -m pip install --upgrade pip +pip install pylint + +# Run pylint +pylint --rcfile=.pylintrc $(git ls-files '*.py')