soham-py 0.1.0__py3-none-any.whl
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.
- soham_py/__init__.py +102 -0
- soham_py/core.py +137 -0
- soham_py/practicals/__init__.py +0 -0
- soham_py/practicals/dbms/__init__.py +1 -0
- soham_py/practicals/dbms/practical1.txt +1 -0
- soham_py/practicals/dbms/practical10.txt +0 -0
- soham_py/practicals/dbms/practical2.txt +1 -0
- soham_py/practicals/dbms/practical3.txt +0 -0
- soham_py/practicals/dbms/practical4.txt +0 -0
- soham_py/practicals/dbms/practical5.txt +0 -0
- soham_py/practicals/dbms/practical6.txt +0 -0
- soham_py/practicals/dbms/practical7.txt +0 -0
- soham_py/practicals/dbms/practical8.txt +0 -0
- soham_py/practicals/dbms/practical9.txt +0 -0
- soham_py/practicals/ds/__init__.py +1 -0
- soham_py/practicals/ds/practical1.txt +0 -0
- soham_py/practicals/ds/practical10.txt +0 -0
- soham_py/practicals/ds/practical2.txt +0 -0
- soham_py/practicals/ds/practical3.txt +0 -0
- soham_py/practicals/ds/practical4.txt +0 -0
- soham_py/practicals/ds/practical5.txt +0 -0
- soham_py/practicals/ds/practical6.txt +0 -0
- soham_py/practicals/ds/practical7.txt +0 -0
- soham_py/practicals/ds/practical8.txt +0 -0
- soham_py/practicals/ds/practical9.txt +0 -0
- soham_py/practicals/wt/__init__.py +1 -0
- soham_py/practicals/wt/practical1.txt +0 -0
- soham_py/practicals/wt/practical10.txt +0 -0
- soham_py/practicals/wt/practical2.txt +0 -0
- soham_py/practicals/wt/practical3.txt +0 -0
- soham_py/practicals/wt/practical4.txt +0 -0
- soham_py/practicals/wt/practical5.txt +0 -0
- soham_py/practicals/wt/practical6.txt +0 -0
- soham_py/practicals/wt/practical7.txt +0 -0
- soham_py/practicals/wt/practical8.txt +0 -0
- soham_py/practicals/wt/practical9.txt +0 -0
- soham_py/saver.py +60 -0
- soham_py/search.py +77 -0
- soham_py/subjects.py +74 -0
- soham_py-0.1.0.dist-info/METADATA +233 -0
- soham_py-0.1.0.dist-info/RECORD +44 -0
- soham_py-0.1.0.dist-info/WHEEL +5 -0
- soham_py-0.1.0.dist-info/licenses/LICENSE +22 -0
- soham_py-0.1.0.dist-info/top_level.txt +1 -0
soham_py/__init__.py
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""SohamPy — College practical programs as importable plain text.
|
|
2
|
+
|
|
3
|
+
A lightweight Python package that bundles college practical programs
|
|
4
|
+
for three subjects (DS, WT, DBMS) as plain ``.txt`` files and lets
|
|
5
|
+
you retrieve them with a simple import.
|
|
6
|
+
|
|
7
|
+
**No stored code is ever executed.**
|
|
8
|
+
|
|
9
|
+
Quick start::
|
|
10
|
+
|
|
11
|
+
import soham_py
|
|
12
|
+
|
|
13
|
+
print(soham_py.ds(1))
|
|
14
|
+
print(soham_py.wt(1))
|
|
15
|
+
print(soham_py.dbms(1))
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from typing import Dict, List, Tuple
|
|
21
|
+
|
|
22
|
+
from .core import get_practical, list_practicals
|
|
23
|
+
from .search import search
|
|
24
|
+
from .saver import save
|
|
25
|
+
from .subjects import get_subjects
|
|
26
|
+
|
|
27
|
+
__version__ = "0.1.0"
|
|
28
|
+
__author__ = "Soham Pandit"
|
|
29
|
+
__all__ = [
|
|
30
|
+
"ds",
|
|
31
|
+
"wt",
|
|
32
|
+
"dbms",
|
|
33
|
+
"list_practicals",
|
|
34
|
+
"subjects",
|
|
35
|
+
"search",
|
|
36
|
+
"save",
|
|
37
|
+
"get_practical",
|
|
38
|
+
"__version__",
|
|
39
|
+
"__author__",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# ── Convenience functions ───────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
def ds(number: int) -> str:
|
|
46
|
+
"""Return the contents of a Data Science practical.
|
|
47
|
+
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
number : int
|
|
51
|
+
Practical number (1–10).
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
str
|
|
56
|
+
Plain-text contents of the practical file.
|
|
57
|
+
"""
|
|
58
|
+
return get_practical("ds", number)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def wt(number: int) -> str:
|
|
62
|
+
"""Return the contents of a Web Technology practical.
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
number : int
|
|
67
|
+
Practical number (1–10).
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
str
|
|
72
|
+
Plain-text contents of the practical file.
|
|
73
|
+
"""
|
|
74
|
+
return get_practical("wt", number)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def dbms(number: int) -> str:
|
|
78
|
+
"""Return the contents of a DBMS practical.
|
|
79
|
+
|
|
80
|
+
Parameters
|
|
81
|
+
----------
|
|
82
|
+
number : int
|
|
83
|
+
Practical number (1–10).
|
|
84
|
+
|
|
85
|
+
Returns
|
|
86
|
+
-------
|
|
87
|
+
str
|
|
88
|
+
Plain-text contents of the practical file.
|
|
89
|
+
"""
|
|
90
|
+
return get_practical("dbms", number)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def subjects() -> List[Tuple[str, str]]:
|
|
94
|
+
"""Return the three primary subjects and their descriptions.
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
list of tuple
|
|
99
|
+
``[(key, description), ...]`` sorted alphabetically.
|
|
100
|
+
"""
|
|
101
|
+
return get_subjects()
|
|
102
|
+
|
soham_py/core.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""Core practical retrieval for SohamPy.
|
|
2
|
+
|
|
3
|
+
This module reads bundled ``.txt`` practical files using
|
|
4
|
+
``importlib.resources`` so the package works after installation without
|
|
5
|
+
depending on the current working directory or absolute paths.
|
|
6
|
+
|
|
7
|
+
**No stored code is ever executed.**
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import sys
|
|
13
|
+
from typing import List
|
|
14
|
+
|
|
15
|
+
from .subjects import (
|
|
16
|
+
PRACTICALS_PER_SUBJECT,
|
|
17
|
+
SUBJECT_INFO,
|
|
18
|
+
resolve_subject,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
# ── importlib.resources compatibility ───────────────────────────────
|
|
22
|
+
# Python 3.9+ has importlib.resources.files; earlier versions need the
|
|
23
|
+
# backport, but we only support >=3.9 so importlib.resources is fine.
|
|
24
|
+
if sys.version_info >= (3, 9):
|
|
25
|
+
from importlib.resources import files
|
|
26
|
+
else: # pragma: no cover – we require >=3.9
|
|
27
|
+
from importlib.resources import files # type: ignore[attr-defined]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _validate_practical_number(number: int) -> None:
|
|
31
|
+
"""Raise ``ValueError`` if *number* is outside 1..PRACTICALS_PER_SUBJECT."""
|
|
32
|
+
if not isinstance(number, int) or isinstance(number, bool):
|
|
33
|
+
raise ValueError(
|
|
34
|
+
f"Practical number must be an integer, got {type(number).__name__}."
|
|
35
|
+
)
|
|
36
|
+
if number < 1 or number > PRACTICALS_PER_SUBJECT:
|
|
37
|
+
raise ValueError(
|
|
38
|
+
f"Practical number must be between 1 and {PRACTICALS_PER_SUBJECT}, "
|
|
39
|
+
f"got {number}."
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def get_practical(subject: str, number: int) -> str:
|
|
44
|
+
"""Return the contents of a practical file as a plain-text string.
|
|
45
|
+
|
|
46
|
+
Parameters
|
|
47
|
+
----------
|
|
48
|
+
subject : str
|
|
49
|
+
Subject name or alias (case-insensitive).
|
|
50
|
+
number : int
|
|
51
|
+
Practical number (1–10).
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
str
|
|
56
|
+
The full contents of the practical file. Returns ``""`` when the
|
|
57
|
+
file is empty.
|
|
58
|
+
|
|
59
|
+
Raises
|
|
60
|
+
------
|
|
61
|
+
ValueError
|
|
62
|
+
If the subject or practical number is invalid.
|
|
63
|
+
FileNotFoundError
|
|
64
|
+
If the underlying resource package or ``.txt`` file is missing.
|
|
65
|
+
"""
|
|
66
|
+
key = resolve_subject(subject)
|
|
67
|
+
_validate_practical_number(number)
|
|
68
|
+
|
|
69
|
+
filename = f"practical{number}.txt"
|
|
70
|
+
resource_package = f"soham_py.practicals.{key}"
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
package_files = files(resource_package)
|
|
74
|
+
except (ModuleNotFoundError, FileNotFoundError) as exc:
|
|
75
|
+
raise FileNotFoundError(
|
|
76
|
+
f"Practical package not found: {resource_package}"
|
|
77
|
+
) from exc
|
|
78
|
+
|
|
79
|
+
resource = package_files.joinpath(filename)
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
return resource.read_text(encoding="utf-8")
|
|
83
|
+
except FileNotFoundError as exc:
|
|
84
|
+
raise FileNotFoundError(
|
|
85
|
+
f"Practical file not found: {key}/{filename}"
|
|
86
|
+
) from exc
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def list_practicals(subject: str) -> List[int]:
|
|
90
|
+
"""Return a sorted list of available practical numbers for *subject*.
|
|
91
|
+
|
|
92
|
+
Parameters
|
|
93
|
+
----------
|
|
94
|
+
subject : str
|
|
95
|
+
Subject name or alias (case-insensitive).
|
|
96
|
+
|
|
97
|
+
Returns
|
|
98
|
+
-------
|
|
99
|
+
list of int
|
|
100
|
+
Practical numbers, e.g. ``[1, 2, 3, ..., 10]``.
|
|
101
|
+
|
|
102
|
+
Raises
|
|
103
|
+
------
|
|
104
|
+
ValueError
|
|
105
|
+
If the subject is invalid.
|
|
106
|
+
FileNotFoundError
|
|
107
|
+
If the underlying resource package or directory is missing.
|
|
108
|
+
"""
|
|
109
|
+
key = resolve_subject(subject)
|
|
110
|
+
resource_package = f"soham_py.practicals.{key}"
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
package_dir = files(resource_package)
|
|
114
|
+
except (ModuleNotFoundError, FileNotFoundError) as exc:
|
|
115
|
+
raise FileNotFoundError(
|
|
116
|
+
f"Practical package not found: {resource_package}"
|
|
117
|
+
) from exc
|
|
118
|
+
|
|
119
|
+
try:
|
|
120
|
+
items = list(package_dir.iterdir())
|
|
121
|
+
except (FileNotFoundError, ModuleNotFoundError) as exc:
|
|
122
|
+
raise FileNotFoundError(
|
|
123
|
+
f"Practical directory not found: {resource_package}"
|
|
124
|
+
) from exc
|
|
125
|
+
|
|
126
|
+
numbers: List[int] = []
|
|
127
|
+
for item in items:
|
|
128
|
+
name = item.name
|
|
129
|
+
if name.startswith("practical") and name.endswith(".txt"):
|
|
130
|
+
stem = name[len("practical"):-len(".txt")]
|
|
131
|
+
if stem.isdigit():
|
|
132
|
+
num = int(stem)
|
|
133
|
+
if 1 <= num <= PRACTICALS_PER_SUBJECT:
|
|
134
|
+
numbers.append(num)
|
|
135
|
+
|
|
136
|
+
return sorted(numbers)
|
|
137
|
+
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
practical 1
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
practical 2
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
soham_py/saver.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Save practical contents to a local file.
|
|
2
|
+
|
|
3
|
+
This module writes the plain-text contents of a practical to a
|
|
4
|
+
user-specified file path. **No stored code is ever executed.**
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import pathlib
|
|
10
|
+
|
|
11
|
+
from .core import get_practical
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def save(subject: str, number: int, output_path: str) -> pathlib.Path:
|
|
15
|
+
"""Save a practical's contents to a local file.
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
subject : str
|
|
20
|
+
Subject name or alias (case-insensitive).
|
|
21
|
+
number : int
|
|
22
|
+
Practical number (1–10).
|
|
23
|
+
output_path : str
|
|
24
|
+
Destination file path.
|
|
25
|
+
|
|
26
|
+
Returns
|
|
27
|
+
-------
|
|
28
|
+
pathlib.Path
|
|
29
|
+
The resolved path of the created file.
|
|
30
|
+
|
|
31
|
+
Raises
|
|
32
|
+
------
|
|
33
|
+
ValueError
|
|
34
|
+
If the subject or practical number is invalid.
|
|
35
|
+
FileNotFoundError
|
|
36
|
+
If the practical file is missing from the package.
|
|
37
|
+
OSError
|
|
38
|
+
If the output path cannot be written to.
|
|
39
|
+
"""
|
|
40
|
+
if not isinstance(output_path, (str, pathlib.Path)):
|
|
41
|
+
raise TypeError(
|
|
42
|
+
f"output_path must be a str or Path, got {type(output_path).__name__}."
|
|
43
|
+
)
|
|
44
|
+
if isinstance(output_path, str) and not output_path.strip():
|
|
45
|
+
raise ValueError("output_path cannot be empty or only whitespace.")
|
|
46
|
+
|
|
47
|
+
content = get_practical(subject, number)
|
|
48
|
+
|
|
49
|
+
dest = pathlib.Path(output_path).resolve()
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
53
|
+
dest.write_text(content, encoding="utf-8")
|
|
54
|
+
except OSError as exc:
|
|
55
|
+
raise OSError(
|
|
56
|
+
f"Could not write to {output_path!r}: {exc}"
|
|
57
|
+
) from exc
|
|
58
|
+
|
|
59
|
+
return dest
|
|
60
|
+
|
soham_py/search.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Search through all bundled practicals for SohamPy.
|
|
2
|
+
|
|
3
|
+
Provides case-insensitive full-text search across every subject and
|
|
4
|
+
practical file. Empty files are silently skipped.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Dict, List
|
|
10
|
+
|
|
11
|
+
from .core import get_practical
|
|
12
|
+
from .subjects import PRACTICALS_PER_SUBJECT, SUBJECT_INFO
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# ── Public search result type ───────────────────────────────────────
|
|
16
|
+
# Each result is a dict with keys: subject, practical, snippet
|
|
17
|
+
|
|
18
|
+
SearchResult = Dict[str, object]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def search(query: str) -> List[SearchResult]:
|
|
22
|
+
"""Search all practicals for *query* (case-insensitive).
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
query : str
|
|
27
|
+
The search term.
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
list of dict
|
|
32
|
+
Each dict contains:
|
|
33
|
+
- ``"subject"`` (str) – canonical subject key
|
|
34
|
+
- ``"practical"`` (int) – practical number
|
|
35
|
+
- ``"snippet"`` (str) – the first line containing the match
|
|
36
|
+
|
|
37
|
+
Raises
|
|
38
|
+
------
|
|
39
|
+
ValueError
|
|
40
|
+
If *query* is empty or contains only whitespace.
|
|
41
|
+
"""
|
|
42
|
+
if not isinstance(query, str) or not query.strip():
|
|
43
|
+
raise ValueError("Search query must be a non-empty string.")
|
|
44
|
+
|
|
45
|
+
term = query.strip().lower()
|
|
46
|
+
results: List[SearchResult] = []
|
|
47
|
+
|
|
48
|
+
for subject_key in sorted(SUBJECT_INFO.keys()):
|
|
49
|
+
for num in range(1, PRACTICALS_PER_SUBJECT + 1):
|
|
50
|
+
try:
|
|
51
|
+
content = get_practical(subject_key, num)
|
|
52
|
+
except FileNotFoundError:
|
|
53
|
+
continue
|
|
54
|
+
|
|
55
|
+
# Skip empty files
|
|
56
|
+
if not content.strip():
|
|
57
|
+
continue
|
|
58
|
+
|
|
59
|
+
# Case-insensitive search
|
|
60
|
+
if term in content.lower():
|
|
61
|
+
# Extract the first matching line as a snippet
|
|
62
|
+
snippet = ""
|
|
63
|
+
for line in content.splitlines():
|
|
64
|
+
if term in line.lower():
|
|
65
|
+
snippet = line.strip()
|
|
66
|
+
break
|
|
67
|
+
|
|
68
|
+
results.append(
|
|
69
|
+
{
|
|
70
|
+
"subject": subject_key,
|
|
71
|
+
"practical": num,
|
|
72
|
+
"snippet": snippet,
|
|
73
|
+
}
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
return results
|
|
77
|
+
|
soham_py/subjects.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Subject definitions and alias resolution for SohamPy.
|
|
2
|
+
|
|
3
|
+
This module defines the three primary subjects (DS, WT, DBMS) and
|
|
4
|
+
provides case-insensitive alias resolution.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Dict, List, Tuple
|
|
8
|
+
|
|
9
|
+
# ── Subject metadata ────────────────────────────────────────────────
|
|
10
|
+
SUBJECT_INFO: Dict[str, str] = {
|
|
11
|
+
"ds": "Data Science",
|
|
12
|
+
"wt": "Web Technology",
|
|
13
|
+
"dbms": "Database Management Systems",
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
# ── Alias mapping (all lowercase) ──────────────────────────────────
|
|
17
|
+
SUBJECT_ALIASES: Dict[str, str] = {
|
|
18
|
+
"ds": "ds",
|
|
19
|
+
"data_science": "ds",
|
|
20
|
+
"wt": "wt",
|
|
21
|
+
"web": "wt",
|
|
22
|
+
"web_technology": "wt",
|
|
23
|
+
"dbms": "dbms",
|
|
24
|
+
"database": "dbms",
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# ── Practical count per subject ─────────────────────────────────────
|
|
28
|
+
PRACTICALS_PER_SUBJECT: int = 10
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def resolve_subject(name: str) -> str:
|
|
32
|
+
"""Resolve a subject name or alias to its canonical key.
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
name : str
|
|
37
|
+
Subject name or alias (case-insensitive).
|
|
38
|
+
|
|
39
|
+
Returns
|
|
40
|
+
-------
|
|
41
|
+
str
|
|
42
|
+
Canonical subject key (``"ds"``, ``"wt"``, or ``"dbms"``).
|
|
43
|
+
|
|
44
|
+
Raises
|
|
45
|
+
------
|
|
46
|
+
ValueError
|
|
47
|
+
If *name* is not a string, is empty, or is not a recognised subject/alias.
|
|
48
|
+
"""
|
|
49
|
+
if not isinstance(name, str):
|
|
50
|
+
raise ValueError(
|
|
51
|
+
f"Subject name must be a string, got {type(name).__name__}."
|
|
52
|
+
)
|
|
53
|
+
key = name.strip().lower().replace(" ", "_")
|
|
54
|
+
if not key:
|
|
55
|
+
raise ValueError("Subject name cannot be empty or only whitespace.")
|
|
56
|
+
if key not in SUBJECT_ALIASES:
|
|
57
|
+
valid = ", ".join(sorted(SUBJECT_ALIASES.keys()))
|
|
58
|
+
raise ValueError(
|
|
59
|
+
f"Invalid subject: {name!r}. "
|
|
60
|
+
f"Valid subjects and aliases are: {valid}"
|
|
61
|
+
)
|
|
62
|
+
return SUBJECT_ALIASES[key]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def get_subjects() -> List[Tuple[str, str]]:
|
|
66
|
+
"""Return a list of ``(key, description)`` tuples for every subject.
|
|
67
|
+
|
|
68
|
+
Returns
|
|
69
|
+
-------
|
|
70
|
+
list of tuple
|
|
71
|
+
Sorted list of ``(subject_key, description)`` pairs.
|
|
72
|
+
"""
|
|
73
|
+
return sorted(SUBJECT_INFO.items())
|
|
74
|
+
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: soham-py
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: College practical programs stored as plain text — retrieve them with a simple Python import.
|
|
5
|
+
Author: Soham Pandit
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Soham117Pandit/soham-py
|
|
8
|
+
Project-URL: Issues, https://github.com/Soham117Pandit/soham-py/issues
|
|
9
|
+
Keywords: practicals,college,data-science,web-technology,dbms
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Education
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Education
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
25
|
+
Requires-Dist: build>=1.0; extra == "dev"
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# SohamPy
|
|
29
|
+
|
|
30
|
+
**College practical programs stored as plain text — retrieve them with a simple Python import.**
|
|
31
|
+
|
|
32
|
+
SohamPy is a lightweight Python package that bundles college practical programs for three subjects as plain `.txt` files. Once installed, you can retrieve any practical from any computer using a simple import statement — no internet connection required after installation.
|
|
33
|
+
|
|
34
|
+
> **Important:** SohamPy stores and returns source code as **plain text**. It never executes the stored code.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Supported Subjects
|
|
39
|
+
|
|
40
|
+
| Key | Subject | Practicals |
|
|
41
|
+
|--------|------------------------------|------------|
|
|
42
|
+
| `ds` | Data Science | 10 |
|
|
43
|
+
| `wt` | Web Technology | 10 |
|
|
44
|
+
| `dbms` | Database Management Systems | 10 |
|
|
45
|
+
|
|
46
|
+
**Total: 30 practical files.**
|
|
47
|
+
|
|
48
|
+
> **Note:** SQL, MySQL, and MongoDB are topics within DBMS — they are not separate subjects.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install soham-py
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
After installation, the package works **completely offline**. Internet is only needed for the initial install and future updates.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Quick Start
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import soham_py
|
|
66
|
+
|
|
67
|
+
# Retrieve a Data Science practical
|
|
68
|
+
print(soham_py.ds(1))
|
|
69
|
+
|
|
70
|
+
# Retrieve a Web Technology practical
|
|
71
|
+
print(soham_py.wt(1))
|
|
72
|
+
|
|
73
|
+
# Retrieve a DBMS practical
|
|
74
|
+
print(soham_py.dbms(1))
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Available Functions
|
|
80
|
+
|
|
81
|
+
### Retrieve a Practical
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
soham_py.ds(1) # Data Science practical 1
|
|
85
|
+
soham_py.wt(5) # Web Technology practical 5
|
|
86
|
+
soham_py.dbms(10) # DBMS practical 10
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Returns the complete contents of the `.txt` file as a Python string. Empty files return `""`.
|
|
90
|
+
|
|
91
|
+
### List Practicals
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
soham_py.list_practicals("ds")
|
|
95
|
+
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
96
|
+
|
|
97
|
+
soham_py.list_practicals("wt")
|
|
98
|
+
soham_py.list_practicals("dbms")
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Show Subjects
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
soham_py.subjects()
|
|
105
|
+
# [('dbms', 'Database Management Systems'),
|
|
106
|
+
# ('ds', 'Data Science'),
|
|
107
|
+
# ('wt', 'Web Technology')]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Search Practicals
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
soham_py.search("regression")
|
|
114
|
+
soham_py.search("database")
|
|
115
|
+
soham_py.search("HTML")
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- Searches all three subjects.
|
|
119
|
+
- Case-insensitive.
|
|
120
|
+
- Skips empty files.
|
|
121
|
+
- Returns a list of `{"subject", "practical", "snippet"}` dicts.
|
|
122
|
+
- Returns `[]` when there are no matches.
|
|
123
|
+
- Raises `ValueError` for empty or whitespace-only queries.
|
|
124
|
+
|
|
125
|
+
### Save a Practical to a File
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
soham_py.save("ds", 1, "practical1.txt")
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
- Saves the practical contents to a local file.
|
|
132
|
+
- Uses UTF-8 encoding.
|
|
133
|
+
- Preserves the original text exactly.
|
|
134
|
+
- You can choose any output filename.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Subject Aliases
|
|
139
|
+
|
|
140
|
+
You can use alternative names for subjects:
|
|
141
|
+
|
|
142
|
+
| Alias | Resolves To |
|
|
143
|
+
|--------------------|-------------|
|
|
144
|
+
| `ds` | `ds` |
|
|
145
|
+
| `data_science` | `ds` |
|
|
146
|
+
| `wt` | `wt` |
|
|
147
|
+
| `web` | `wt` |
|
|
148
|
+
| `web_technology` | `wt` |
|
|
149
|
+
| `dbms` | `dbms` |
|
|
150
|
+
| `database` | `dbms` |
|
|
151
|
+
|
|
152
|
+
All aliases are **case-insensitive**.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Adding Your Practical Programs
|
|
157
|
+
|
|
158
|
+
All 30 practical files are **initially empty**. To add your code:
|
|
159
|
+
|
|
160
|
+
1. Find the package source in `src/soham_py/practicals/`.
|
|
161
|
+
2. Open the appropriate `.txt` file (e.g., `ds/practical1.txt`).
|
|
162
|
+
3. Paste your practical program as plain text.
|
|
163
|
+
4. Rebuild and reinstall the package.
|
|
164
|
+
|
|
165
|
+
```text
|
|
166
|
+
src/soham_py/practicals/
|
|
167
|
+
├── ds/
|
|
168
|
+
│ ├── practical1.txt ← Add your DS practical 1 code here
|
|
169
|
+
│ ├── practical2.txt
|
|
170
|
+
│ └── ...
|
|
171
|
+
├── wt/
|
|
172
|
+
│ ├── practical1.txt ← Add your WT practical 1 code here
|
|
173
|
+
│ └── ...
|
|
174
|
+
└── dbms/
|
|
175
|
+
├── practical1.txt ← Add your DBMS practical 1 code here
|
|
176
|
+
└── ...
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
> **Note:** After modifying practicals in a published package, you must create a new version and upgrade via `pip install --upgrade soham-py` for the changes to take effect on other computers.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Error Handling
|
|
184
|
+
|
|
185
|
+
| Situation | Error Raised |
|
|
186
|
+
|--------------------------|---------------------|
|
|
187
|
+
| Invalid subject name | `ValueError` |
|
|
188
|
+
| Invalid practical number | `ValueError` |
|
|
189
|
+
| Missing practical file | `FileNotFoundError` |
|
|
190
|
+
| Empty search query | `ValueError` |
|
|
191
|
+
| Empty practical file | Returns `""` (no error) |
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Development
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# Clone the repository
|
|
199
|
+
git clone https://github.com/soham-pandit/soham-py.git
|
|
200
|
+
cd soham-py
|
|
201
|
+
|
|
202
|
+
# Install in editable mode with dev dependencies
|
|
203
|
+
pip install -e ".[dev]"
|
|
204
|
+
|
|
205
|
+
# Run tests
|
|
206
|
+
pytest -v
|
|
207
|
+
|
|
208
|
+
# Build distributions
|
|
209
|
+
python -m build
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Contributing
|
|
215
|
+
|
|
216
|
+
1. Fork the repository.
|
|
217
|
+
2. Create a feature branch.
|
|
218
|
+
3. Make your changes.
|
|
219
|
+
4. Run the tests.
|
|
220
|
+
5. Submit a pull request.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## License
|
|
225
|
+
|
|
226
|
+
This project is licensed under the **MIT License** — see the [LICENSE](LICENSE) file for details.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Author
|
|
231
|
+
|
|
232
|
+
**Soham Pandit**
|
|
233
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
soham_py/__init__.py,sha256=5npobTUItXjokuPvDMSxt0WiNIquDcUQkcOYpu6OEuo,2141
|
|
2
|
+
soham_py/core.py,sha256=PEsFk7AF8C_VolfCUMdWiC-U-FgGyz_LyVOAjSrOHkw,4115
|
|
3
|
+
soham_py/saver.py,sha256=w32SknCNzxaf6LqXipDAGcfhNhi0yrVR7M8X7vgJBGw,1593
|
|
4
|
+
soham_py/search.py,sha256=ae-8vLv3osyhZKmRcecBFFYgmCtfevrOJipvX5W0_EM,2252
|
|
5
|
+
soham_py/subjects.py,sha256=pc0xqcgyPLNwLf9B1RMX35LaqX_vT0lV1fsI02rAgbQ,2269
|
|
6
|
+
soham_py/practicals/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
soham_py/practicals/dbms/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
8
|
+
soham_py/practicals/dbms/practical1.txt,sha256=OwSzn9ZJv6qc4ylHD-ZFYjlsu-V5qCz0WBrCC6elYYU,11
|
|
9
|
+
soham_py/practicals/dbms/practical10.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
soham_py/practicals/dbms/practical2.txt,sha256=CLyIZqUYH8XZRBBVQvuc9IS1JVBDaS34qB8Vzqru5Ls,11
|
|
11
|
+
soham_py/practicals/dbms/practical3.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
soham_py/practicals/dbms/practical4.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
soham_py/practicals/dbms/practical5.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
soham_py/practicals/dbms/practical6.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
+
soham_py/practicals/dbms/practical7.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
soham_py/practicals/dbms/practical8.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
+
soham_py/practicals/dbms/practical9.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
|
+
soham_py/practicals/ds/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
19
|
+
soham_py/practicals/ds/practical1.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
+
soham_py/practicals/ds/practical10.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
+
soham_py/practicals/ds/practical2.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
+
soham_py/practicals/ds/practical3.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
+
soham_py/practicals/ds/practical4.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
+
soham_py/practicals/ds/practical5.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
|
+
soham_py/practicals/ds/practical6.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
|
+
soham_py/practicals/ds/practical7.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
|
+
soham_py/practicals/ds/practical8.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
|
+
soham_py/practicals/ds/practical9.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
|
+
soham_py/practicals/wt/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
30
|
+
soham_py/practicals/wt/practical1.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
|
+
soham_py/practicals/wt/practical10.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
32
|
+
soham_py/practicals/wt/practical2.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
|
+
soham_py/practicals/wt/practical3.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
|
+
soham_py/practicals/wt/practical4.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
|
+
soham_py/practicals/wt/practical5.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
|
+
soham_py/practicals/wt/practical6.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
37
|
+
soham_py/practicals/wt/practical7.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
|
+
soham_py/practicals/wt/practical8.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
39
|
+
soham_py/practicals/wt/practical9.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
|
+
soham_py-0.1.0.dist-info/licenses/LICENSE,sha256=a-s_os0nmTksPgwOTyaHAtQ8lFh5x_IoUAVuVpa6quc,1070
|
|
41
|
+
soham_py-0.1.0.dist-info/METADATA,sha256=VeVk8Qvq9ULx3bSTUb6yT1eDkIvgUtwteDxOurkSPRk,6155
|
|
42
|
+
soham_py-0.1.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
43
|
+
soham_py-0.1.0.dist-info/top_level.txt,sha256=JjFUeW76_mn93BMXNyCUQpWhClo8e3l44XPcNkMgD-A,9
|
|
44
|
+
soham_py-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Soham Pandit
|
|
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.
|
|
22
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
soham_py
|