sparq 0.1.0__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.
sparq-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Shiven Sheth
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
sparq-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 2.4
2
+ Name: sparq
3
+ Version: 0.1.0
4
+ Summary: Python client for the sparq api - automated degree planning for SJSU students + more
5
+ Author: Shiven Sheth
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/shiventi/sparq
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.8
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: requests>=2.25.0
14
+ Dynamic: license-file
15
+
16
+ # sparq Client
17
+
18
+ Python client library for the sparq API - automated degree planning for SJSU students.
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pip install sparq
sparq-0.1.0/README.md ADDED
@@ -0,0 +1,8 @@
1
+ # sparq Client
2
+
3
+ Python client library for the sparq API - automated degree planning for SJSU students.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install sparq
sparq-0.1.0/auth.py ADDED
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import requests
4
+ import os
5
+ from pathlib import Path
6
+
7
+ API_URL = "https://sparq-api.onrender.com"
8
+
9
+ def save_api_key(api_key, email):
10
+ config_dir = Path.home() / ".sparq"
11
+ config_dir.mkdir(exist_ok=True)
12
+ config_file = config_dir / "config.txt"
13
+
14
+ with open(config_file, "w") as f:
15
+ f.write(f"API_KEY={api_key}\n")
16
+ f.write(f"EMAIL={email}\n")
17
+
18
+ print(f"\nAPI key saved to {config_file}")
19
+
20
+ def register():
21
+ email = input("Email: ").strip()
22
+
23
+ if not email or "@" not in email:
24
+ print("Invalid email address")
25
+ return
26
+
27
+ response = requests.post(
28
+ f"{API_URL}/register",
29
+ json={"email": email},
30
+ headers={"Content-Type": "application/json"}
31
+ )
32
+
33
+ if response.status_code == 200:
34
+ data = response.json()
35
+ if data.get("status") == "pending_verification":
36
+ print("Code already sent. Check your email.")
37
+ else:
38
+ print("Verification code sent to your email")
39
+ elif response.status_code != 200:
40
+ print(response.json()['detail'])
41
+ return
42
+
43
+ code = input("Enter code: ").strip()
44
+
45
+ response = requests.post(
46
+ f"{API_URL}/verify",
47
+ json={"email": email, "code": code},
48
+ headers={"Content-Type": "application/json"}
49
+ )
50
+
51
+ if response.status_code == 200:
52
+ api_key = response.json()["api_key"]
53
+ print(f"\nAPI Key: {api_key}")
54
+ save_api_key(api_key, email)
55
+ else:
56
+ print(response.json()['detail'])
57
+
58
+ if __name__ == "__main__":
59
+ register()
60
+
sparq-0.1.0/client.py ADDED
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import requests
4
+ from pathlib import Path
5
+
6
+ API_URL = "https://sparq-api.onrender.com"
7
+
8
+ class Sparq:
9
+ def __init__(self, api_key=None):
10
+ if api_key:
11
+ self.api_key = api_key
12
+ else:
13
+ self.api_key = self._load_api_key()
14
+
15
+ def _load_api_key(self):
16
+ config_file = Path.home() / ".sparq" / "config.txt"
17
+ if config_file.exists():
18
+ with open(config_file, "r") as f:
19
+ for line in f:
20
+ if line.startswith("API_KEY="):
21
+ return line.strip().split("=", 1)[1]
22
+ return None
23
+
24
+ def plan(self, major, cc_courses=None, ap_exams=None, sjsu_courses=None, units_per_semester=15):
25
+ if not self.api_key:
26
+ raise Exception("No API key found. Run auth.py first.")
27
+
28
+ payload = {
29
+ "major": major,
30
+ "cc_courses": cc_courses or [],
31
+ "ap_exams": ap_exams or [],
32
+ "sjsu_courses": sjsu_courses or [],
33
+ "units_per_semester": units_per_semester
34
+ }
35
+
36
+ response = requests.post(
37
+ f"{API_URL}/plan",
38
+ json=payload,
39
+ headers={
40
+ "Content-Type": "application/json",
41
+ "x-api-key": self.api_key
42
+ }
43
+ )
44
+
45
+ if response.status_code == 200:
46
+ return response.json()
47
+ else:
48
+ raise Exception(f"Error: {response.json().get('detail', 'Unknown error')}")
49
+
50
+ def usage(self):
51
+ """Get API usage statistics for the authenticated user."""
52
+ if not self.api_key:
53
+ raise Exception("No API key found. Run auth.py first.")
54
+
55
+ response = requests.get(
56
+ f"{API_URL}/usage",
57
+ params={"x_api_key": self.api_key}
58
+ )
59
+
60
+ if response.status_code == 200:
61
+ return response.json()
62
+ else:
63
+ raise Exception(f"Error: {response.json().get('detail', 'Unknown error')}")
@@ -0,0 +1,27 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "sparq"
7
+ version = "0.1.0"
8
+ authors = [
9
+ { name="Shiven Sheth" }
10
+ ]
11
+ description = "Python client for the sparq api - automated degree planning for SJSU students + more"
12
+ readme = "README.md"
13
+ requires-python = ">=3.8"
14
+ license = {text = "MIT"}
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "Operating System :: OS Independent",
18
+ ]
19
+ dependencies = [
20
+ "requests>=2.25.0",
21
+ ]
22
+
23
+ [project.urls]
24
+ Homepage = "https://github.com/shiventi/sparq"
25
+
26
+ [tool.setuptools]
27
+ py-modules = ["client", "auth", "recover", "usage", "sparq"]
sparq-0.1.0/recover.py ADDED
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import requests
4
+ from pathlib import Path
5
+
6
+ API_URL = "https://sparq-api.onrender.com"
7
+
8
+ def save_api_key(api_key, email):
9
+ config_dir = Path.home() / ".sparq"
10
+ config_dir.mkdir(exist_ok=True)
11
+ config_file = config_dir / "config.txt"
12
+
13
+ with open(config_file, "w") as f:
14
+ f.write(f"API_KEY={api_key}\n")
15
+ f.write(f"EMAIL={email}\n")
16
+
17
+ print(f"\nAPI key saved to {config_file}")
18
+
19
+ def recover():
20
+ email = input("Email: ").strip()
21
+
22
+ if not email or "@" not in email:
23
+ print("Invalid email address")
24
+ return
25
+
26
+ response = requests.post(
27
+ f"{API_URL}/recover",
28
+ json={"email": email},
29
+ headers={"Content-Type": "application/json"}
30
+ )
31
+
32
+ if response.status_code != 200:
33
+ print(response.json()['detail'])
34
+ return
35
+
36
+ print("Verification code sent to your email")
37
+
38
+ code = input("Enter code: ").strip()
39
+
40
+ response = requests.post(
41
+ f"{API_URL}/recover",
42
+ json={"email": email, "code": code},
43
+ headers={"Content-Type": "application/json"}
44
+ )
45
+
46
+ if response.status_code == 200:
47
+ api_key = response.json()["api_key"]
48
+ print(f"\nAPI Key: {api_key}")
49
+ save_api_key(api_key, email)
50
+ else:
51
+ print(response.json()['detail'])
52
+
53
+ if __name__ == "__main__":
54
+ recover()
sparq-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 2.4
2
+ Name: sparq
3
+ Version: 0.1.0
4
+ Summary: Python client for the sparq api - automated degree planning for SJSU students + more
5
+ Author: Shiven Sheth
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/shiventi/sparq
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.8
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: requests>=2.25.0
14
+ Dynamic: license-file
15
+
16
+ # sparq Client
17
+
18
+ Python client library for the sparq API - automated degree planning for SJSU students.
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pip install sparq
@@ -0,0 +1,13 @@
1
+ LICENSE
2
+ README.md
3
+ auth.py
4
+ client.py
5
+ pyproject.toml
6
+ recover.py
7
+ sparq.py
8
+ usage.py
9
+ sparq.egg-info/PKG-INFO
10
+ sparq.egg-info/SOURCES.txt
11
+ sparq.egg-info/dependency_links.txt
12
+ sparq.egg-info/requires.txt
13
+ sparq.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ requests>=2.25.0
@@ -0,0 +1,5 @@
1
+ auth
2
+ client
3
+ recover
4
+ sparq
5
+ usage
sparq-0.1.0/sparq.py ADDED
@@ -0,0 +1,39 @@
1
+ from client import Sparq
2
+
3
+ client = Sparq("your-api-key-here")
4
+
5
+ # edit accordingly
6
+ plan = client.plan(
7
+ major= "Computer Science",
8
+ cc_courses= [
9
+ # EVC Courses (based on actual transcript)
10
+ {"code": "COMSC 075", "title": "Computer Science I", "grade": "A", "institution": "Evergreen Valley College"},
11
+ {"code": "COMSC 076", "title": "Computer Science II", "grade": "A", "institution": "Evergreen Valley College"},
12
+ {"code": "COMS 020", "title": "Oral Communication", "grade": "A", "institution": "Evergreen Valley College"},
13
+ {"code": "ART 096", "title": "History of Asian Art", "grade": "A", "institution": "Evergreen Valley College"},
14
+ {"code": "COMS 035", "title": "Intercultural Communication", "grade": "A", "institution": "Evergreen Valley College"},
15
+ {"code": "PSYCH 001", "title": "General Psychology", "grade": "A", "institution": "Evergreen Valley College"},
16
+ {"code": "PHIL 060", "title": "Logic and Critical Thinking", "grade": "A", "institution": "Evergreen Valley College"},
17
+ {"code": "PHIL 010", "title": "Introduction to Philosophy", "grade": "A", "institution": "Evergreen Valley College"},
18
+ {"code": "PHIL 065", "title": "Introduction to Ethics", "grade": "A", "institution": "Evergreen Valley College"},
19
+ {"code": "COMSC 080", "title": "Discrete Structures", "grade": "A", "institution": "Evergreen Valley College"},
20
+ {"code": "HIST 017A", "title": "History of the United States", "grade": "A", "institution": "Evergreen Valley College"},
21
+ # SJCC Courses
22
+ {"code": "ENGL 001A", "title": "English Composition", "grade": "A", "institution": "San Jose City College"},
23
+ ],
24
+ ap_exams= [
25
+ {"test": "Calculus AB", "score": 5},
26
+ {"test": "Calculus BC", "score": 4},
27
+ {"test": "World History", "score": 4},
28
+ {"test": "Physics C, Mechanics", "score": 4},
29
+ ],
30
+ sjsu_courses= [
31
+ {"code": "MATH 32", "title": "Calculus III", "status": "In Progress", "term": "Fall 2025"},
32
+ {"code": "CS 49J", "title": "Programming in Java", "status": "In Progress", "term": "Fall 2025"},
33
+ {"code": "NUFS 16", "title": "Nutrition", "status": "In Progress", "term": "Fall 2025"},
34
+ {"code": "METR 10", "title": "Weather and Climate", "status": "In Progress", "term": "Fall 2025"},
35
+ ],
36
+ units_per_semester= 15
37
+ )
38
+
39
+ print(plan)
sparq-0.1.0/usage.py ADDED
@@ -0,0 +1,55 @@
1
+ import requests
2
+ from pathlib import Path
3
+
4
+ API_URL = "http://localhost:8000"
5
+
6
+ def load_api_key():
7
+ config_path = Path.home() / ".sparq" / "config.txt"
8
+ if not config_path.exists():
9
+ return None
10
+ with open(config_path, "r") as f:
11
+ for line in f:
12
+ if line.startswith("API_KEY="):
13
+ return line.strip().split("=", 1)[1]
14
+ return None
15
+
16
+ def view_usage(api_key=None):
17
+ if not api_key:
18
+ api_key = load_api_key()
19
+ if not api_key:
20
+ print("No API key found. Please run auth.py to register first.")
21
+ return
22
+
23
+ try:
24
+ response = requests.get(
25
+ f"{API_URL}/usage",
26
+ headers={"x-api-key": api_key}
27
+ )
28
+
29
+ if response.status_code == 200:
30
+ data = response.json()
31
+
32
+ print(f"\nEmail: {data['email']}")
33
+ print(f"Total API Calls: {data['total_api_calls']}\n")
34
+
35
+ if data['recent_calls']:
36
+ print("Recent Calls:")
37
+ for i, call in enumerate(data['recent_calls'], 1):
38
+ major = call.get('request_data', {}).get('major', 'N/A') if call.get('request_data') else 'N/A'
39
+ print(f" {i}. {call['endpoint']} | {call['response_status']} | {major} | {call['created_at']}")
40
+ else:
41
+ print("No API calls recorded yet.\n")
42
+
43
+ elif response.status_code == 401:
44
+ print("Invalid or inactive API key")
45
+ else:
46
+ print(f"Error: {response.json().get('detail', 'Unknown error')}")
47
+
48
+ except requests.exceptions.ConnectionError:
49
+ print(f"Cannot connect to API at {API_URL}")
50
+ print("Make sure the server is running")
51
+ except Exception as e:
52
+ print(f"Error: {e}")
53
+
54
+ if __name__ == "__main__":
55
+ view_usage()