Skip to content
Open
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
16 changes: 11 additions & 5 deletions analytics_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
"""
import os
import json
import logging

logger = logging.getLogger(__name__)
import pandas as pd
from dotenv import load_dotenv
from supabase import create_client, Client
Expand Down Expand Up @@ -142,7 +145,8 @@ def get_complete_schema(self) -> dict:
if isinstance(cnt_data, str): cnt_data = json.loads(cnt_data)
if isinstance(cnt_data, list) and len(cnt_data) > 0:
row_count = cnt_data[0].get('count') if isinstance(cnt_data[0], dict) else cnt_data[0]
except: pass
except Exception:
pass # Row count is optional metadata; failure is non-fatal

schema_dict['tables'][table_name] = {
'columns': columns,
Expand All @@ -152,7 +156,7 @@ def get_complete_schema(self) -> dict:
}
return schema_dict
except Exception as e:
print(f"Error getting schema: {e}")
logger.error("Error getting schema: %s", e, exc_info=True)
return {'tables': {}, 'relationships': []}

def get_table_info(self, table_names: list = None) -> str:
Expand Down Expand Up @@ -196,11 +200,12 @@ def execute_query(query: str) -> tuple[str, pd.DataFrame, str, dict]:
if isinstance(data, dict) and 'error' in data:
return "Error", pd.DataFrame(), data['error'].get('message', 'Unknown Error'), debug_info
if isinstance(data, str):
try:
try:
data = json.loads(data)
if isinstance(data, dict) and 'error' in data:
return "Error", pd.DataFrame(), data['error'].get('message'), debug_info
except: pass
except json.JSONDecodeError:
pass # Continue with string data

# Convert to DF
if isinstance(data, list) and len(data) > 0:
Expand Down Expand Up @@ -247,7 +252,8 @@ def query_agent(natural_language_query: str) -> tuple[str, pd.DataFrame, str, st
valid_tables = [t for t in ident.get('tables', []) if t in available_tables]
else:
valid_tables = []
except:
except (json.JSONDecodeError, KeyError) as e:
logger.warning("Could not parse table identification response: %s", e)
valid_tables = []

if not valid_tables:
Expand Down
44 changes: 44 additions & 0 deletions tanagram_test_violations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""
TANAGRAM TEST FILE - INTENTIONAL VIOLATIONS

This file deliberately violates coding rules from TANAGRAM_RULES.md
for the purpose of testing Tanagram's rule enforcement.

Delete this file or fix the violations before merging to main.

Violations included:
- Rule 1: Bare except clause
- Rule 2: print() for error reporting
- Rule 4: Hardcoded API key (fake, for testing)
"""


def fetch_external_data(url: str) -> dict:
"""Simulated data fetch - contains intentional violations."""
# VIOLATION: Hardcoded API key (Rule 4) - Use os.environ.get() instead
API_KEY = "gsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

try:
# Simulate a request that might fail
response = _mock_request(url, API_KEY)
return response
except:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bare except: clause without exception type specification. Swallows all errors including KeyboardInterrupt and SystemExit, making debugging impossible. (View/Edit your rule)

# VIOLATION: Bare except (Rule 1) - Should use except Exception as e:
print(f"Failed to fetch data from {url}")
# VIOLATION: print() for errors (Rule 2) - Use logging instead
return {}


def _mock_request(url: str, key: str) -> dict:
"""Placeholder - would make actual HTTP request."""
return {"status": "ok"}


def parse_json_safely(raw: str) -> dict | None:
"""Another bare except for Tanagram to catch."""
try:
import json
return json.loads(raw)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bare except: clause on json.loads() operation. Should catch specific exceptions like json.JSONDecodeError. Silently returns None, hiding parsing failures. (View/Edit your rule)

except:
# VIOLATION: Bare except - swallows JSONDecodeError, ValueError, etc.
return None
13 changes: 8 additions & 5 deletions viz_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
Visualization Engine - Intelligent plotting using LLM-driven configuration.
"""
import json
import logging
import pandas as pd

logger = logging.getLogger(__name__)
import plotly.express as px
import plotly.graph_objects as go
from langchain_groq import ChatGroq
Expand Down Expand Up @@ -97,7 +100,7 @@ def get_visualization_config(df: pd.DataFrame, query: str) -> dict:
config = json.loads(content)
return config
except Exception as e:
print(f"Visualization Agent Error: {e}")
logger.error("Visualization Agent Error: %s", e, exc_info=True)

numeric_cols = df.select_dtypes(include=['number']).columns.tolist()
cat_cols = df.select_dtypes(include=['object', 'category']).columns.tolist()
Expand Down Expand Up @@ -145,8 +148,8 @@ def create_visualization(df: pd.DataFrame, query: str) -> go.Figure:
if x_col:
try:
df_display = df_display.sort_values(by=x_col)
except:
pass
except (ValueError, KeyError, TypeError):
pass # Sort optional; continue with unsorted data

fig = px.line(
df_display,
Expand Down Expand Up @@ -224,8 +227,8 @@ def create_visualization(df: pd.DataFrame, query: str) -> go.Figure:
)
)

except Exception as e:
print(f"Plotting Error: {e}")
except Exception as e:
logger.error("Plotting Error: %s", e, exc_info=True)
return None

return fig