diff --git a/.github/workflows/learn-github-action.yml b/.github/workflows/learn-github-action.yml new file mode 100644 index 00000000..d19ef2fc --- /dev/null +++ b/.github/workflows/learn-github-action.yml @@ -0,0 +1,23 @@ +name: cs5500PIPLINE + +defaults: + run: + shell: bash + + +on: + push: + branches: + - main + + pull_request: + branches: + - main +jobs: + run-tests: + runs-on: macos-latest + steps: + - run: echo "šŸŽ‰ Hello World!" + - run: echo "🐧" + - run: echo "šŸ”Ž" + diff --git a/.gitignore b/.gitignore index 14d7fa72..70d2d7d1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ .idea __pycache__ .DS_Store +.env +env/ \ No newline at end of file diff --git a/SPRINT1.md b/SPRINT1.md new file mode 100644 index 00000000..ae829299 --- /dev/null +++ b/SPRINT1.md @@ -0,0 +1,63 @@ +# Project: Case Management API Development SPRINT1 +## OCT. 9th - OCT. 23rd +## Contributors +- Han Yang, Hao Luo, Ruiyi Li, Ruimeng +## Overview +This project aims to create a RESTful API to manage and analyze client data in a case management service. The backend is developed using **FastAPI** and connected to a cloud-based **MySQL** database hosted on **AWS RDS**. The system facilitates CRUD operations and predictive analytics to assist in making informed decisions for clients’ employment outcomes. + +## Team Collaboration + +### 1. Database Service Selection +As a team, we discussed and evaluated several options for hosting the database. After considering various factors like scalability, security, and ease of use, we decided to use **Amazon RDS (AWS Relational Database Service)** for hosting our **MySQL** database. This choice was driven by the need for an online, centralized database solution that would allow all team members to connect remotely and collaborate effectively. + +### 2. REST API Knowledge Sharing +To ensure that all team members were on the same page, we conducted a series of discussions and knowledge-sharing sessions about REST API concepts. This was crucial in helping everyone understand the following: +- How to structure API endpoints for CRUD operations. +- Best practices for data validation using **Pydantic** models. +- Implementation of asynchronous processing with **FastAPI**. + +These sessions enabled team members to independently develop API functions, ensuring consistency in design and implementation across the project. + +### 3. Development Plan +To manage the project effectively, we outlined a comprehensive development plan that included the following stages: + +#### Phase 1: Setup & Initialization +- Create a virtual environment and install dependencies from `requirements.txt`. +- Initialize the FastAPI project structure and set up the database schema using **MySQL Workbench**. + +#### Phase 2: Database Configuration +- Register for AWS services and create an RDS instance with MySQL. +- Set up security groups and VPC configuration to allow external access to the database. +- Establish the connection between FastAPI and the AWS-hosted MySQL database. + +#### Phase 3: API Development +- Develop core API endpoints for CRUD operations on client data: + - **POST /clients/predictions**: Accepts client data and returns prediction results. + - **GET /clients/{id}**: Retrieves client information by ID. + - **PUT /clients/{id}**: Updates client information by ID. + - **DELETE /clients/{id}**: Deletes client data by ID. +- Implement data validation using Pydantic models. +- Write unit tests for each endpoint to ensure functionality and reliability. + +#### Phase 4: Testing & Documentation +- Conduct end-to-end testing using **Postman** and manual verification of database changes. +- Document API endpoints using FastAPI’s interactive Swagger documentation. +- Create user guides and detailed instructions for API usage, including connection setup and deployment. + +#### Phase 5: Final Review & Deployment +- Perform final testing to ensure all components work together seamlessly. +- Deploy the API on a cloud server, ensuring continuous integration and delivery. + +### 4. AWS Registration & Database Connection +We successfully registered for AWS, created an RDS instance, and configured it for public access. This involved: +- Setting up inbound rules in the security group to allow access to port **3306** from our IP addresses. +- Modifying VPC settings to enable public accessibility. +- Establishing the connection between MySQL Workbench and the RDS instance, allowing us to manage the database and import CSV data. + +With the database setup complete, the backend is now fully functional, providing efficient API access to case management data. + +## Future Work +- Enhance predictive analytics by integrating additional ML models. +- Implement OAuth2 for user authentication. +- Add logging and monitoring for improved error handling and performance tracking. + diff --git a/SPRINT2.md b/SPRINT2.md new file mode 100644 index 00000000..24871b92 --- /dev/null +++ b/SPRINT2.md @@ -0,0 +1,66 @@ +# SPRINT 2: Project Progress Summary + +## Overview +Following the completion of SPRINT 1, we focused on enhancing the core functionality of our Case Management API project. This involved connecting team members to the centralized database, building a robust connection manager, adjusting the database schema, and developing comprehensive REST API endpoints. + +## Accomplishments + +### 1. Establishing Database Connectivity for All Team Members +- Successfully configured and connected all team members to the **AWS RDS MySQL database**. +- Ensured that each member could access the database through **PyCharm** and other SQL clients by setting up appropriate security group rules and connection details. + +### 2. Developing a Connection Manager +- Implemented a `ConnectionManager` class to streamline database connections for the project: + ```python + import mysql.connector + import os + from mysql.connector import pooling + from dotenv import load_dotenv + + class ConnectionManager: + def __init__(self): + self.db_config = { + "host": os.getenv("DB_HOST"), + "port": int(os.getenv("DB_PORT")), + "user": os.getenv("DB_USER"), + "password": os.getenv("DB_PASSWORD"), + "database": os.getenv("DB_NAME") + } + + # Create a connection pool + self.pool = pooling.MySQLConnectionPool( + pool_name="mypool", + pool_size=5, + **self.db_config + ) + + # Get a connection + def get_connection(self): + return self.pool.get_connection() + + # Close the connection + def close_connection(self, connection): + if connection.is_connected(): + connection.close() + +This manager ensures efficient connection handling using a pool to maintain stability and optimize performance. +### 3. Adjusting the Database Schema + - Updated the clients table schema to match the PredictionInput model. This involved creating a schema that accurately reflects the data structure needed for client information. + - Sample schema adjustment included: + - Modifying column data types to align with the PredictionInput requirements. + - Adding or updating fields to store client-specific data effectively. +### 4. Developing REST API Endpoints + - Implemented the core REST API functionalities for client data management: + - GET endpoint to retrieve client information. + - POST endpoint to add new client data. + - DELETE endpoint to remove client data. + - PUT endpoint to update existing client information. + +## Next Steps + Moving forward, we will: + + - Perform thorough testing and validation of the new REST API endpoints. + - Implement security measures, such as user authentication and data encryption. + - Integrate advanced data processing or analytics features to enhance API capabilities. +## Conclusion +SPRINT 2 has solidified the core infrastructure of our project by ensuring database connectivity for all team members, creating a connection manager for efficient data handling, adjusting the database schema for proper client data storage, and developing essential REST API functionalities. This progress lays a strong foundation for further development and upcoming sprints. \ No newline at end of file diff --git a/SPRINT3.md b/SPRINT3.md new file mode 100644 index 00000000..e31ae278 --- /dev/null +++ b/SPRINT3.md @@ -0,0 +1,78 @@ +# SPRINT 3: Project Progress Summary + +## Overview +In Sprint 3, we focused on testing, enhancing, and documenting the core functionality of our database service project for frontend engineers. The sprint objectives included ensuring seamless database connectivity, improving user experience by handling edge cases, adding robust tests, and creating a user guide tailored to our target audience. + +## Accomplishments + +### 1. Testing Database Connectivity +We validated the connection between the application and the MySQL database to ensure reliability: +- Confirmed that the application could create, update, retrieve, and delete data from the database without errors. +- Addressed initial connection challenges by refining configurations for the connection pool. +### 2. All CRUD API EndPoints Implemented +We implemented all api endpoints: +- GET: clients/ --> get all clients +- GET: clients/{id} --> get client by id +- POST: clients/ --> Insert a new client with proper body +- UPDATE: clients/{id} --> Update Client information with partial body + - DELETE: clients/{id} --> Delete Record by id from the database +### 3. Adjusting Database Design +We restructured the database to improve efficiency and support future scalability: +- Adjusted database field types to better align with data requirements, optimizing storage and query performance. +- Defined a new **primary tree** structure to enhance data organization and retrieval. This adjustment allows for a more logical and hierarchical representation of related entities in the database. +- Updated documentation to reflect the new database design, ensuring compatibility with frontend engineers’ needs. + +### 4. Running the Project for Database Operations +Documented the steps to set up the project and interact with the database, ensuring smooth onboarding for developers: +- Verified that all endpoints worked correctly for editing and retrieving database content. +- Ensured developers could replicate the process in their local environments. + +**Example of Running the Project:** + +# Set up virtual environment and install dependencies +python3 -m venv env +source env/bin/activate +pip install -r requirements.txt + +# Start the server +uvicorn app.main:app --reload + +### 4. Adding Edge Cases +We expanded functionality to handle uncommon user scenarios and improve overall robustness: +- Implemented input validation to manage invalid or missing data. +- Enhanced error handling with detailed, user-friendly error messages. +- In Sprint 3, we made our database service more reliable and easier to use. The API now handles problems like missing or incomplete client data by showing clear error messages instead of crashing. For example, if the age field is missing in a request, the API will respond with a message explaining the issue. We also tested all the endpoints thoroughly to make sure they work well. Additionally, we created a user guide to help frontend engineers set up and use the service easily. These improvements prepare us well for the next steps in the project. + +### 5. Writing and Running Tests +We developed and executed tests to ensure the reliability of the database operations: +Created unit and integration tests for the following API endpoints: +- POST to add new client data. +- GET to retrieve client information by ID. +- PUT to update existing client records. +- DELETE to remove client records. +Verified edge case handling through additional test cases. +Ensured the tests passed successfully, confirming system stability. +**Example Test Structure:** +def test_get_client(): + response = client.get("/clients/1") + assert response.status_code == 200 + assert response.json()["id"] == 1 + +### 6. Writing a User Guide +We created a user guide tailored to frontend engineers, outlining: +- Steps to set up the project environment. +- Instructions for using the API endpoints. +- Guidance on handling common errors and testing the endpoints. +- Ensured the guide is clear and easy to follow for our target market. + +## Next Steps +- Increase Test Coverage +Add more test cases for the same endpoint to validate handling of different scenarios, ensuring robustness and consistency. +- Update Edge Case Handling +Implement logic to handle consecutive identical POST requests gracefully, avoiding redundant entries or unexpected errors. +Add functionality to provide a clear and informative response when a user attempts to delete a non-existent account. +- Refactor and Optimize Code Structure +Adjust the project environment by transferring part of the codebase into router.py to improve modularity and maintainability. + +## Conclusion +Sprint 3 has strengthened the foundation of our project by ensuring database connectivity, addressing edge cases, adding comprehensive tests, and documenting the process for frontend engineers. This progress positions us well for further enhancements in upcoming sprints. diff --git a/User Guide.md b/User Guide.md new file mode 100644 index 00000000..78f02b4d --- /dev/null +++ b/User Guide.md @@ -0,0 +1,168 @@ +# User Guide for Database Service API + +This guide provides instructions to help frontend engineers integrate and utilize the database service API. + +--- + +## 1. Introduction + +The Database Service API allows frontend engineers to: +- Manage client information. +- Generate predictions based on client data. +- Perform CRUD operations with ease. + +**Base URL:** +`https://api.yourservice.com` + +--- + +## 2. Setup Instructions + +### Install Dependencies +To set up the application, install all required Python packages: +```bash +pip install -r requirements.txt +``` + +### Set Up a Virtual Environment +Using a virtual environment ensures isolated dependency management. + +**Create the Virtual Environment:** +```bash +python3 -m venv env +# For Windows: +python -m venv env +``` + +**Activate the Virtual Environment:** +```bash +# For macOS/Linux: +source env/bin/activate + +# For Windows: +env\Scripts\activate +``` + +### Run the Application +Start the server with the following command: +```bash +uvicorn app.main:app --reload +``` +The application will be accessible at `http://127.0.0.1:8000`. + +--- + +## 3. API Endpoints + +### Client Management + +#### Create a New Client +- **Endpoint:** + `POST /clients` + +- **Description:** + Creates a new client record in the database. + +- **Request Example:** + ```json + { + "age": 30, + "gender": "female", + "work_experience": 5, + "housing": "rented" + } + ``` + +- **Response Example:** + ```json + { + "id": 1, + "age": 30, + "gender": "female" + } + ``` + +#### Retrieve Client Details +- **Endpoint:** + `GET /clients/{id}` + +- **Description:** + Fetches details of a specific client by their unique ID. + +- **Request Example:** + `GET /clients/1` + +- **Response Example:** + ```json + { + "id": 1, + "age": 30, + "gender": "female" + } + ``` + +#### Update Client Information +- **Endpoint:** + `PUT /clients/{id}` + +- **Description:** + Updates the details of an existing client. + +- **Request Example:** + ```json + { + "age": 31 + } + ``` + +- **Response Example:** + ```json + { + "id": 1, + "age": 31, + "gender": "female" + } + ``` + +#### Delete a Client +- **Endpoint:** + `DELETE /clients/{id}` + +- **Description:** + Deletes a client record by their unique ID. + +- **Response Example:** + HTTP 204 No Content (indicates success). + +--- + +## 4. Error Handling + +| Error Code | Description | Solution | +|------------|------------------------------|--------------------------------------| +| 400 | Invalid input or missing fields | Verify and correct your request. | +| 401 | Unauthorized access | Ensure your API key is correct. | +| 404 | Resource not found | Verify the endpoint and resource ID. | +| 500 | Internal server error | Retry or contact support. | + +--- + +## 5. Accessing the API Documentation + +You can explore and test all endpoints interactively using: +- **Swagger UI:** [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) +- **ReDoc:** [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) + +--- + +## 6. Frequently Asked Questions (FAQ) + +### Can I test the API without coding? +Yes! Use the Swagger UI linked above to interact with the API. + +### What if I encounter a 500 Internal Server Error? +Retry the request after some time. If the issue persists, contact technical support. + +### Can I use a different language for integration? +Absolutely. Our API is language-agnostic and supports HTTP requests from any programming language. +``` diff --git a/app/clients/ConnectionManager.py b/app/clients/ConnectionManager.py new file mode 100644 index 00000000..4b755446 --- /dev/null +++ b/app/clients/ConnectionManager.py @@ -0,0 +1,30 @@ +import mysql.connector +import os +from mysql.connector import pooling +from dotenv import load_dotenv +load_dotenv() +class ConnectionManager: + def __init__(self): + self.db_config = { + "host": os.getenv("DB_HOST"), + "port": int(os.getenv("DB_PORT")), + "user": os.getenv("DB_USER"), + "password": os.getenv("DB_PASSWORD"), + "database": os.getenv("DB_NAME") + } + + # Create a connection pool + self.pool = pooling.MySQLConnectionPool( + pool_name="mypool", + pool_size=5, + **self.db_config + ) + + # Get a connection + def get_connection(self): + return self.pool.get_connection() + + # Close the connection + def close_connection(self, connection): + if connection.is_connected(): + connection.close() diff --git a/app/clients/router.py b/app/clients/router.py index f860c402..f96e713f 100644 --- a/app/clients/router.py +++ b/app/clients/router.py @@ -1,15 +1,150 @@ +from http.client import HTTPException + from fastapi import APIRouter -from fastapi.responses import HTMLResponse +from fastapi import HTTPException +from app.clients.schema import PredictionInput as Client +from app.clients.schema import ClientUpdate as DynamicClient +from app.clients.ConnectionManager import ConnectionManager from app.clients.service.logic import interpret_and_calculate from app.clients.schema import PredictionInput router = APIRouter(prefix="/clients", tags=["clients"]) +# HEIHEIHEI @router.post("/predictions") async def predict(data: PredictionInput): print("HERE") print(data.model_dump()) return interpret_and_calculate(data.model_dump()) +@router.get("/") +async def get_all(): + try: + connection_manager = ConnectionManager() + connection = connection_manager.get_connection() + cursor = connection.cursor(dictionary=True) + query = "SELECT * FROM clients" + cursor.execute(query) + clients = cursor.fetchall() + cursor.close() + + if not clients: + raise HTTPException(status_code=404, detail=f"No clients found") + else: + return clients + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) +@router.get("/{id}") +async def get_by_id(id: int): + try: + connection_manager = ConnectionManager() + connection = connection_manager.get_connection() + + cursor = connection.cursor(dictionary=True) + query = f"SELECT * FROM clients WHERE client_id = {id}" + cursor.execute(query) + client = cursor.fetchone() + + cursor.close() + connection_manager.close_connection(connection) + + if not client: + raise HTTPException(status_code=404, detail=f"Client with id {id} not found") + return client + + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/") +async def create_client(client: Client): + try: + connection_manager = ConnectionManager() + connection = connection_manager.get_connection() + + cursor = connection.cursor(dictionary=True) + query = """ + INSERT INTO clients ( + age, gender, work_experience, canada_workex, dep_num, + canada_born, citizen_status, level_of_schooling, fluent_english, + reading_english_scale, speaking_english_scale, writing_english_scale, + numeracy_scale, computer_scale, transportation_bool, caregiver_bool, + housing, income_source, felony_bool, attending_school, + currently_employed, substance_use, time_unemployed, need_mental_health_support_bool + ) VALUES ( + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s + ) + """ + cursor.execute(query, ( + client.age, client.gender, client.work_experience, client.canada_workex, + client.dep_num, client.canada_born, client.citizen_status, client.level_of_schooling, + client.fluent_english, client.reading_english_scale, client.speaking_english_scale, + client.writing_english_scale, client.numeracy_scale, client.computer_scale, + client.transportation_bool, client.caregiver_bool, client.housing, + client.income_source, client.felony_bool, client.attending_school, + client.currently_employed, client.substance_use, client.time_unemployed, + client.need_mental_health_support_bool + )) + connection.commit() + cursor.close() + connection_manager.close_connection(connection) + return {"message": "Client created successfully"} + except Exception as e: + raise HTTPException(status_code=500, + detail=f"Internal server error: {str(e)}") + + + +@router.put("/{id}") +async def update_client(id: int, data: DynamicClient): + try: + connection_manager = ConnectionManager() + connection = connection_manager.get_connection() + cursor = connection.cursor(dictionary=True) + + update_fields = [] + update_values = [] + for field, value in data.model_dump(exclude_unset=True).items(): + update_fields.append(f"{field} = %s") + update_values.append(value) + if not update_fields: + raise HTTPException(status_code=400, + detail="No fields provided for update") + update_values.append(id) + query = f""" + UPDATE clients + SET {', '.join(update_fields)} + WHERE client_id = %s + """ + cursor.execute(query, tuple(update_values)) + connection.commit() + if cursor.rowcount == 0: + raise HTTPException(status_code=404, detail=f"Client with id {id} not found") + + cursor.close() + connection_manager.close_connection(connection) + + return {"message": f"Client id {id} updated successfully"} + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + +@router.delete("/{id}") +async def delete_client(id: int): + try: + connection_manager = ConnectionManager() + connection = connection_manager.get_connection() + cursor = connection.cursor(dictionary=True) + query = "DELETE FROM clients WHERE client_id = %s" + cursor.execute(query, (id,)) + + if cursor.rowcount == 0: + raise HTTPException(status_code=404, detail=f"Client with id {id} not found") + connection.commit() + connection_manager.close_connection(connection) + cursor.close() + return {"message": "Client deleted successfully"} + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + diff --git a/app/clients/schema.py b/app/clients/schema.py index 6b56ad98..09a90f23 100644 --- a/app/clients/schema.py +++ b/app/clients/schema.py @@ -1,5 +1,5 @@ from pydantic import BaseModel - +from typing import Optional class PredictionInput(BaseModel): age: int gender: str @@ -25,3 +25,30 @@ class PredictionInput(BaseModel): substance_use: str time_unemployed: int need_mental_health_support_bool: str + +# Pydantic Model for Request Body Validation +class ClientUpdate(BaseModel): + age: Optional[int] = None + gender: Optional[str] = None + work_experience: Optional[int] = None + canada_workex: Optional[int] = None + dep_num: Optional[int] = None + canada_born: Optional[str] = None + citizen_status: Optional[str] = None + level_of_schooling: Optional[str] = None + fluent_english: Optional[str] = None + reading_english_scale: Optional[int] = None + speaking_english_scale: Optional[int] = None + writing_english_scale: Optional[int] = None + numeracy_scale: Optional[int] = None + computer_scale: Optional[int] = None + transportation_bool: Optional[str] = None + caregiver_bool: Optional[str] = None + housing: Optional[str] = None + income_source: Optional[str] = None + felony_bool: Optional[str] = None + attending_school: Optional[str] = None + currently_employed: Optional[str] = None + substance_use: Optional[str] = None + time_unemployed: Optional[int] = None + need_mental_health_support_bool: Optional[str] = None \ No newline at end of file diff --git a/app/clients/service/model.py b/app/clients/service/model.py index 51369ac3..5863e918 100644 --- a/app/clients/service/model.py +++ b/app/clients/service/model.py @@ -5,7 +5,6 @@ from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestRegressor - def prepare_models(): # Load dataset and define the features and labels backendCode = pd.read_csv('data_commontool.csv') diff --git a/app/main.py b/app/main.py index 5b6bf162..4d9ee441 100644 --- a/app/main.py +++ b/app/main.py @@ -1,11 +1,13 @@ -from fastapi import FastAPI +from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware +from app.clients.ConnectionManager import ConnectionManager from app.clients.router import router as clients_router app = FastAPI() + # Set API endpoints on router app.include_router(clients_router) @@ -17,4 +19,20 @@ allow_headers=["*"], # Allows all headers ) +# Test ConnectionManager +@app.get("/test-connection") +async def test_connection(): + try: + connection_manager = ConnectionManager() + connection = connection_manager.get_connection() + if connection.is_connected(): + connection_manager.close_connection(connection) + return {"message": "Connection to the database was successful!"} + else: + raise HTTPException(status_code=500, detail="Connection to the database failed.") + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + + + diff --git a/requirements.txt b/requirements.txt index 1ccf75b7..84ecfd3c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,142 +1,115 @@ +adjustText==0.8 aiofiles==23.2.1 alembic==1.12.0 annotated-types==0.6.0 anyio==3.7.1 appnope==0.1.3 -argon2-cffi==21.3.0 -argon2-cffi-bindings==21.2.0 -arrow==1.2.3 astroid==3.0.1 asttokens==2.4.0 -attrs==22.1.0 +attrs==23.1.0 backcall==0.2.0 bcrypt==4.0.1 -beautifulsoup4==4.12.2 black==23.10.0 -bleach==6.0.0 -branca==0.6.0 +blinker==1.8.2 +Cartopy==0.22.0 certifi==2023.7.22 cffi==1.16.0 charset-normalizer==3.3.2 click==8.1.7 -comm==0.1.3 +click-plugins==1.1.1 +cligj==0.7.2 +comm==0.2.0 +contourpy==1.2.0 cryptography==41.0.4 -debugpy==1.6.7 +cycler==0.12.1 +debugpy==1.8.0 decorator==5.1.1 -defusedxml==0.7.1 dill==0.3.7 ecdsa==0.18.0 -exceptiongroup==1.0.4 +et-xmlfile==1.1.0 executing==2.0.0 fastapi==0.103.2 -fastjsonschema==2.16.3 -folium==0.14.0 -fqdn==1.5.1 +fiona==1.9.5 +Flask==3.0.3 +fonttools==4.46.0 +geographiclib==2.0 +geopandas==0.14.1 +geopy==2.4.1 h11==0.14.0 httptools==0.6.0 idna==3.4 -iniconfig==1.1.1 -ipykernel==6.22.0 +ipykernel==6.27.1 ipython==8.16.1 -ipython-genutils==0.2.0 -ipywidgets==8.0.6 -isoduration==20.11.0 isort==5.12.0 +itsdangerous==2.2.0 jedi==0.19.1 Jinja2==3.1.2 -joblib==1.4.0 -jsonpointer==2.3 -jsonschema==4.17.3 -jupyter==1.0.0 -jupyter-console==6.6.3 -jupyter-events==0.6.3 -jupyter_client==8.2.0 -jupyter_core==5.3.0 -jupyter_server==2.5.0 -jupyter_server_terminals==0.4.4 -jupyterlab-pygments==0.2.2 -jupyterlab-widgets==3.0.7 -lxml==4.9.3 +jupyter_client==8.6.0 +jupyter_core==5.5.0 +kiwisolver==1.4.5 Mako==1.2.4 MarkupSafe==2.1.3 +matplotlib==3.8.2 matplotlib-inline==0.1.6 mccabe==0.7.0 -mistune==2.0.5 mypy-extensions==1.0.0 -nbclassic==0.5.5 -nbclient==0.7.3 -nbconvert==7.3.1 -nbformat==5.8.0 -nest-asyncio==1.5.6 -notebook==6.5.4 -notebook_shim==0.2.2 -numpy==1.24.2 +mysql-connector-python==9.1.0 +mysqlclient==2.2.5 +nest-asyncio==1.5.8 +networkx==3.2.1 +numpy==1.26.2 +openpyxl==3.1.2 packaging==23.2 -pandas==2.0.0 -pandocfilters==1.5.0 +pandas==2.1.4 parso==0.8.3 passlib==1.7.4 pathspec==0.11.2 pexpect==4.8.0 pickleshare==0.7.5 +Pillow==10.1.0 platformdirs==3.11.0 -pluggy==1.0.0 -prometheus-client==0.16.0 +plotly==5.18.0 prompt-toolkit==3.0.39 -psutil==5.9.5 +psutil==5.9.6 psycopg2-binary==2.9.9 ptyprocess==0.7.0 pure-eval==0.2.2 pyasn1==0.5.0 -pycodestyle==2.10.0 pycparser==2.21 pydantic==2.4.2 pydantic-settings==2.0.3 pydantic_core==2.10.1 Pygments==2.16.1 pylint==3.0.1 -pyrsistent==0.19.3 -pytest==7.2.0 +pyparsing==3.1.1 +pyproj==3.6.1 +pyshp==2.3.1 python-dateutil==2.8.2 python-dotenv==1.0.0 python-jose==3.3.0 -python-json-logger==2.0.7 python-multipart==0.0.6 -pytz==2023.3 +pytz==2023.3.post1 PyYAML==6.0.1 -pyzmq==25.0.2 -qtconsole==5.4.2 -QtPy==2.3.1 +pyzmq==25.1.2 requests==2.31.0 -rfc3339-validator==0.1.4 -rfc3986-validator==0.1.1 rsa==4.9 -scikit-learn==1.4.2 -scipy==1.13.0 -Send2Trash==1.8.0 +shapely==2.0.2 six==1.16.0 sniffio==1.3.0 -soupsieve==2.4.1 SQLAlchemy==2.0.21 stack-data==0.6.3 starlette==0.27.0 -terminado==0.17.1 -threadpoolctl==3.4.0 -tinycss2==1.2.1 -tomli==2.0.1 +tenacity==8.2.3 tomlkit==0.12.1 -tornado==6.3.1 +tornado==6.4 traitlets==5.11.2 typing_extensions==4.8.0 tzdata==2023.3 -uri-template==1.2.0 urllib3==2.0.7 uvicorn==0.23.2 uvloop==0.17.0 watchfiles==0.20.0 wcwidth==0.2.8 -webcolors==1.13 -webencodings==0.5.1 -websocket-client==1.5.1 websockets==11.0.3 -widgetsnbextension==4.0.7 +Werkzeug==3.1.2 +scikit-learn \ No newline at end of file