QuantumChecker 0.3.2__tar.gz → 0.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: QuantumChecker
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: A package to evaluate homework submissions in Python, SQL, PowerBI, and SSIS.
5
5
  Author: Qobiljon
6
6
  Author-email: qobiljonkhayrullayev@gmail.com
@@ -17,22 +17,37 @@ import base64
17
17
 
18
18
  def prompt_text_powerbi(combined_content: str) -> str:
19
19
  return f"""
20
- Evaluate the following Power BI DAX question-answer pairs for correctness, clarity, and appropriateness.
21
- Provide an overall score out of 100 and concise feedback. Focus on DAX logic and structure.
22
- Structure the response as:
23
- OVERALL SCORE: [SCORE]/100
24
- [FEEDBACK]
20
+ You are an expert Power BI instructor evaluating beginner-level DAX question-answer pairs.
21
+
22
+ Each answer contains a data model (in JSON format) extracted from a submitted .pbit file. Evaluate the technical correctness, relevance, and clarity of the DAX elements provided.
23
+
24
+ Use the following criteria to give a fair and supportive evaluation:
25
+ - Measures (40 points): Are calculated measures meaningful, syntactically valid, and aligned with the question?
26
+ - Relationships (20 points): Are key relationships between tables defined logically?
27
+ - Tables & Columns (20 points): Are relevant tables/columns present? Are naming conventions clear?
28
+ - Expressions (10 points): Are query partitions or expressions present and understandable?
29
+ - Overall structure (10 points): Does the model appear coherent and purposeful?
30
+
31
+ **Scoring Tolerance**:
32
+ - Be kind to beginners. Do not give extremely low scores unless the model is completely missing or incorrect.
33
+ - If measures exist and make some sense, award partial credit (e.g., 20–30 out of 40).
34
+ - A score below 30/100 should only be given if there’s little to no relevant content.
35
+
36
+ Structure your response exactly like this:
37
+ OVERALL SCORE: [SCORE]/100
38
+ [Brief feedback here — 3–5 sentences focused on strengths + areas to improve.]
39
+ {combined_content}
40
+ """
25
41
 
26
- {combined_content}
27
- """
28
42
 
29
43
 
30
44
  load_dotenv()
31
45
  logger = logging.getLogger(__name__)
46
+
32
47
  logging.basicConfig(
33
48
  level=logging.INFO,
34
49
  format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
35
- handlers=[logging.FileHandler("../powerbi_evaluator.log"), logging.StreamHandler()]
50
+ handlers=[logging.StreamHandler()]
36
51
  )
37
52
 
38
53
 
@@ -10,7 +10,7 @@ from pprint import pprint
10
10
  import json
11
11
  import re
12
12
 
13
- from .prompts import prompt_text_ssis # Assumes this is defined in .prompts
13
+ from .prompts import prompt_text_ssis
14
14
 
15
15
  logger = logging.getLogger(__name__)
16
16
 
@@ -90,7 +90,7 @@ class SSISAnswerParser:
90
90
  "issues": []
91
91
  }
92
92
 
93
- # Parse package info
93
+
94
94
  package_info = {
95
95
  "Package Name": root.attrib.get("{www.microsoft.com/SqlServer/Dts}ObjectName", "Unknown"),
96
96
  "Creation Date": root.attrib.get("{www.microsoft.com/SqlServer/Dts}CreationDate", "Unknown"),
@@ -101,7 +101,7 @@ class SSISAnswerParser:
101
101
  structured_data["package_info"] = package_info
102
102
  summary.append(f"Package: {package_info['Package Name']} (Created: {package_info['Creation Date']})")
103
103
 
104
- # Parse package description from comments
104
+
105
105
  package_description = "No description found"
106
106
  comment_pattern = re.compile(r'<!--\s*Package Description:\s*(.*?)\s*-->', re.DOTALL)
107
107
  match = comment_pattern.search(content)
@@ -109,7 +109,7 @@ class SSISAnswerParser:
109
109
  package_description = match.group(1).strip()
110
110
  summary.append(f"Description: {package_description}")
111
111
 
112
- # Parse connection managers
112
+
113
113
  for conn in root.findall(".//DTS:ConnectionManager", namespace):
114
114
  try:
115
115
  conn_name = conn.attrib.get("{www.microsoft.com/SqlServer/Dts}ObjectName", "Unnamed Connection")
@@ -133,14 +133,14 @@ class SSISAnswerParser:
133
133
  summary.append(
134
134
  f"Connection: {conn_name} ({conn_type}, ConnectionString: {conn_details['ConnectionString']})")
135
135
  structured_data["connections"].append(conn_details)
136
- # Validate connection
136
+
137
137
  if conn_type == "OLEDB" and "Initial Catalog" not in conn_details["ConnectionString"]:
138
138
  structured_data["issues"].append(f"OLEDB Connection {conn_name} missing database specification")
139
139
  except AttributeError as e:
140
140
  structured_data["issues"].append(f"Error parsing connection {conn_name}: {str(e)}")
141
141
  logger.error("Error parsing connection %s: %s", conn_name, str(e))
142
142
 
143
- # Parse variables
143
+
144
144
  for var in root.findall(".//DTS:Variable", namespace):
145
145
  try:
146
146
  var_name = var.attrib.get("{www.microsoft.com/SqlServer/Dts}ObjectName", "Unnamed Variable")
@@ -155,7 +155,7 @@ class SSISAnswerParser:
155
155
  structured_data["issues"].append(f"Error parsing variable {var_name}: {str(e)}")
156
156
  logger.error("Error parsing variable %s: %s", var_name, str(e))
157
157
 
158
- # Parse data flow components
158
+
159
159
  component_ids = set()
160
160
  for component in root.findall(".//DTS:Executables//component", namespace):
161
161
  try:
@@ -168,7 +168,7 @@ class SSISAnswerParser:
168
168
  structured_data["issues"].append(f"Error parsing component {comp_name}: {str(e)}")
169
169
  logger.error("Error parsing component %s: %s", comp_name, str(e))
170
170
 
171
- # Parse data flow paths
171
+
172
172
  for path in root.findall(".//DTS:Executables//path", namespace):
173
173
  try:
174
174
  start_id = path.attrib.get("startId", "Unknown Start")
@@ -183,14 +183,14 @@ class SSISAnswerParser:
183
183
  structured_data["issues"].append(f"Error parsing path {path_name}: {str(e)}")
184
184
  logger.error("Error parsing path %s: %s", path_name, str(e))
185
185
 
186
- # Additional validations
186
+
187
187
  if not structured_data["connections"]:
188
188
  structured_data["issues"].append("No connections configured in the package")
189
189
  if not structured_data["data_flow_paths"]:
190
190
  structured_data["issues"].append("No data flow paths configured in the package")
191
191
 
192
192
  combined_summary = "\n".join(summary)[:2000] or "No components found in SSIS package"
193
- # Split summary into logical sections for multiple questions
193
+
194
194
  answers = []
195
195
  sections = ["Package", "Description", "Connection", "Variable", "Component", "Data Flow Path"]
196
196
  current_section = []
@@ -207,7 +207,7 @@ class SSISAnswerParser:
207
207
  logger.warning("No valid answers found in single SSIS file")
208
208
  answers = [combined_summary]
209
209
 
210
- # Save structured data for debugging
210
+
211
211
  with open("parsed_ssis_summary.json", "w", encoding="utf-8") as f:
212
212
  json.dump(structured_data, f, indent=2)
213
213
  logger.info("Saved structured SSIS summary to 'parsed_ssis_summary.json'")
@@ -337,7 +337,7 @@ class SSISEvaluator:
337
337
  """
338
338
  try:
339
339
  if answer_path.lower().endswith(".zip"):
340
- # Use provided temp_dir or generate a default one
340
+
341
341
  temp_dir = temp_dir or f"temp_ssis_extract_{os.getpid()}"
342
342
  parsed_data = SSISAnswerParser.parse_zip_file(answer_path, temp_dir)
343
343
  elif answer_path.lower().endswith('.dtsx'):
@@ -361,17 +361,17 @@ class SSISEvaluator:
361
361
  logger.info("Processing %d questions and %d answers", len(questions), len(answers))
362
362
  pprint(f"Processing {len(questions)} questions and {len(answers)} answers")
363
363
 
364
- # Map answers to questions
364
+
365
365
  if not answers:
366
366
  logger.warning("No answers parsed from SSIS file")
367
367
  answers = ["No valid SSIS components found"] * len(questions)
368
368
  elif len(answers) < len(questions):
369
- # Cycle through answers to match question count
369
+
370
370
  answers = [answers[i % len(answers)] for i in range(len(questions))]
371
371
  logger.debug("Expanded %d answers to %d for %d questions", len(parsed_data["text_answers"]),
372
372
  len(answers), len(questions))
373
373
  elif len(answers) > len(questions):
374
- # Truncate to match question count
374
+
375
375
  answers = answers[:len(questions)]
376
376
  logger.debug("Truncated %d answers to %d for %d questions", len(parsed_data["text_answers"]),
377
377
  len(answers), len(questions))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: QuantumChecker
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: A package to evaluate homework submissions in Python, SQL, PowerBI, and SSIS.
5
5
  Author: Qobiljon
6
6
  Author-email: qobiljonkhayrullayev@gmail.com
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="QuantumChecker",
5
- version="0.3.2",
5
+ version="0.3.4",
6
6
  author="Qobiljon",
7
7
  author_email="qobiljonkhayrullayev@gmail.com",
8
8
  description="A package to evaluate homework submissions in Python, SQL, PowerBI, and SSIS.",
File without changes
File without changes