Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added additional API endpoints in api_catch.py #108

Merged
merged 1 commit into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "pycatcher"
version = "0.0.63"
version = "0.0.64"
description = "This package identifies outlier(s) for a given time-series dataset in simple steps. It supports day, week, month and quarter level time-series data."
authors = ["Aseem Anand <[email protected]>"]
maintainers = ["Jagadish Pamarthi <[email protected]>"]
Expand Down
67 changes: 66 additions & 1 deletion src/pycatcher/api_catch.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import pandas as pd
from src.pycatcher.catch import find_outliers_iqr
from src.pycatcher.catch import (find_outliers_iqr, detect_outliers_stl, detect_outliers_today_classic)

# Define the FastAPI app
app = FastAPI(
Expand Down Expand Up @@ -48,5 +48,70 @@ async def find_outliers_api(inputs: InputModel):

return OutputModel(outliers=outliers_list)

except Exception as e:
raise HTTPException(status_code=500, detail=str(e))


@app.post("/detect_outliers_stl", response_model=OutputModel, summary="Detect outliers using STL")
async def detect_outliers_stl_api(inputs: InputModel):
"""
API endpoint to detect outliers using the STL method.
"""
try:
# Convert input data into a pandas DataFrame
df = pd.DataFrame(data=inputs.data, columns=inputs.columns)

# Ensure the first column is in datetime format
if not pd.api.types.is_datetime64_any_dtype(df.iloc[:, 0]):
try:
df.iloc[:, 0] = pd.to_datetime(df.iloc[:, 0])
except Exception as e:
raise HTTPException(status_code=400, detail=f"Error converting first column to datetime: {e}")

# Call the `detect_outliers_stl` function
if not callable(detect_outliers_stl):
raise HTTPException(status_code=500, detail="`detect_outliers_stl` is not defined or not callable")

# Call the function and get the result
outliers = detect_outliers_stl(df)

# Check if the result is a DataFrame
if isinstance(outliers, pd.DataFrame):
outliers_list = outliers.reset_index().to_dict(orient="records")
else:
raise HTTPException(status_code=400, detail="No outliers detected or an error occurred.")

return OutputModel(outliers=outliers_list)

except Exception as e:
raise HTTPException(status_code=500, detail=str(e))


@app.post("/detect_outliers_today_classic", response_model=OutputModel, summary="Detect today's outliers using "
"Classic method")
async def detect_outliers_today_classic_api(inputs: InputModel):
"""
API endpoint to detect today's outliers using the Classic method.
"""
try:
df = pd.DataFrame(data=inputs.data, columns=inputs.columns)

if not pd.api.types.is_datetime64_any_dtype(df.iloc[:, 0]):
try:
df.iloc[:, 0] = pd.to_datetime(df.iloc[:, 0])
except Exception as e:
raise HTTPException(status_code=400, detail=f"Error converting first column to datetime: {e}")

outliers = detect_outliers_today_classic(df)

if isinstance(outliers, pd.DataFrame):
outliers_list = outliers.reset_index().to_dict(orient="records")
elif isinstance(outliers, str): # Handle the "No Outliers Today!" case
outliers_list = [{"message": outliers}]
else:
raise HTTPException(status_code=400, detail="Unexpected output from the function.")

return OutputModel(outliers=outliers_list)

except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
60 changes: 60 additions & 0 deletions tests/test_api_catch.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
from src.pycatcher.api_catch import app
import pandas as pd

# Create a TestClient instance for the FastAPI app
client = TestClient(app)

def test_find_outliers_api():
# Create a TestClient instance for the FastAPI app
client = TestClient(app)
Expand Down Expand Up @@ -40,4 +43,61 @@ def test_find_outliers_api():
f"Expected outliers {expected_outliers}, but got {response_data['outliers']}"
)

def test_detect_outliers_stl_api():
# Prepare test data
data = {
'ID': [1, 2, 3, 4, 5],
'Value': [10, 12, 14, 100, 15]
}
df = pd.DataFrame(data)
payload = {
"data": df.values.tolist(),
"columns": df.columns.tolist()
}

response = client.post("/detect_outliers_stl", json=payload)

# Expected output
expected_outliers = [
{'ID': '1970-01-01T00:00:00', 'Value': 100.0, 'index': 3}
]

assert response.status_code == 200
response_data = response.json()
assert "outliers" in response_data

# Validate the outliers detected
assert response_data["outliers"] == expected_outliers, (
f"Expected outliers {expected_outliers}, but got {response_data['outliers']}"
)

def test_detect_outliers_today_classic_api():
# Prepare test data
data = {
'ID': [1, 2, 3, 4, 5],
'Value': [10, 12, 14, 100, 15]
}

df = pd.DataFrame(data)
payload = {
"data": df.values.tolist(),
"columns": df.columns.tolist()
}

response = client.post("/detect_outliers_today_classic", json=payload)

# Expected output
expected_outliers = [
{'message': 'No Outliers Today!'}
]

assert response.status_code == 200
response_data = response.json()
assert "outliers" in response_data

# Validate the outliers detected
assert response_data["outliers"] == expected_outliers, (
f"Expected outliers {expected_outliers}, but got {response_data['outliers']}"
)

print("Test passed: The API detected outliers correctly.")
Loading