stsdb 0.1.1__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.
stsdb-0.1.1/PKG-INFO ADDED
@@ -0,0 +1,102 @@
1
+ Metadata-Version: 2.4
2
+ Name: stsdb
3
+ Version: 0.1.1
4
+ Summary: Deterministic Slay the Spire card and relic query toolset
5
+ Author: Taardisaa
6
+ License: MIT
7
+ Keywords: slay-the-spire,database,cards,relics
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3 :: Only
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.9
13
+ Description-Content-Type: text/markdown
14
+
15
+ # Slay the Spire Database (stsdb)
16
+
17
+ A card/relic query toolset for [Slay the Spire](https://www.megacrit.com/).
18
+
19
+ It exposes two main commands:
20
+
21
+ - `query_card`: query card metadata, with optional upgrade level.
22
+ - `query_relic`: query relic metadata.
23
+
24
+ Both commands use exact name matching only (no fuzzy match, no partial match, no fallback).
25
+
26
+ `query_card` also supports `upgrade_times`:
27
+
28
+ - Most cards: capped at one applied upgrade.
29
+ - `Searing Blow`: supports unbounded upgrades using the in-game scaling rule.
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ pip install stsdb
35
+ ```
36
+
37
+ Dev installation:
38
+
39
+ ```bash
40
+ pip install -e .
41
+ ```
42
+
43
+ ### Usage
44
+
45
+ ```bash
46
+ stsdb query_card "Bash"
47
+ stsdb query_card "Searing Blow" --upgrade-times 3
48
+ stsdb query_relic "Burning Blood"
49
+ python -m stsdb query_card "Bash"
50
+ ```
51
+
52
+ ### Python API
53
+
54
+ ```python
55
+ import stsdb
56
+ from stsdb import query_card, query_relic
57
+
58
+ stsdb.query_card("Bash")
59
+ query_card("Bash")
60
+ query_card("Searing Blow", upgrade_times=3)
61
+ query_relic("Burning Blood")
62
+ ```
63
+
64
+ ### Local development
65
+
66
+ Install in development mode:
67
+
68
+ ```bash
69
+ pip install -e .
70
+ ```
71
+
72
+ Run tests:
73
+
74
+ ```bash
75
+ python -m unittest discover -s tests -v
76
+ ```
77
+
78
+ ### Output
79
+
80
+ - Success: `{"found": true, "entry": {...}}`
81
+ - Card miss: `{"found": false, "error": "CARD_NOT_FOUND"}`
82
+ - Invalid upgrade input: `{"found": false, "error": "INVALID_UPGRADE_TIMES"}`
83
+ - Relic miss: `{"found": false, "error": "RELIC_NOT_FOUND"}`
84
+
85
+ ## Other Notes
86
+
87
+ Data files are shipped inside the package under `stsdb/data/`:
88
+
89
+ - `card.csv`
90
+ - `relic.csv`
91
+ - `hero.csv`
92
+ - `play.csv`
93
+ - `relic_availability.csv`
94
+ - `card_upgrade.csv`
95
+
96
+ Upgrade metadata format (`card_upgrade.csv`):
97
+
98
+ - `nameCard;hasUpgrade;costUpgraded;descriptionUpgraded`
99
+
100
+ ## Credits
101
+
102
+ This repository is adapted from the original project by [Ferdomgar97](https://github.com/ferdomgar97/Slay-the-Spire)
stsdb-0.1.1/README.md ADDED
@@ -0,0 +1,88 @@
1
+ # Slay the Spire Database (stsdb)
2
+
3
+ A card/relic query toolset for [Slay the Spire](https://www.megacrit.com/).
4
+
5
+ It exposes two main commands:
6
+
7
+ - `query_card`: query card metadata, with optional upgrade level.
8
+ - `query_relic`: query relic metadata.
9
+
10
+ Both commands use exact name matching only (no fuzzy match, no partial match, no fallback).
11
+
12
+ `query_card` also supports `upgrade_times`:
13
+
14
+ - Most cards: capped at one applied upgrade.
15
+ - `Searing Blow`: supports unbounded upgrades using the in-game scaling rule.
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ pip install stsdb
21
+ ```
22
+
23
+ Dev installation:
24
+
25
+ ```bash
26
+ pip install -e .
27
+ ```
28
+
29
+ ### Usage
30
+
31
+ ```bash
32
+ stsdb query_card "Bash"
33
+ stsdb query_card "Searing Blow" --upgrade-times 3
34
+ stsdb query_relic "Burning Blood"
35
+ python -m stsdb query_card "Bash"
36
+ ```
37
+
38
+ ### Python API
39
+
40
+ ```python
41
+ import stsdb
42
+ from stsdb import query_card, query_relic
43
+
44
+ stsdb.query_card("Bash")
45
+ query_card("Bash")
46
+ query_card("Searing Blow", upgrade_times=3)
47
+ query_relic("Burning Blood")
48
+ ```
49
+
50
+ ### Local development
51
+
52
+ Install in development mode:
53
+
54
+ ```bash
55
+ pip install -e .
56
+ ```
57
+
58
+ Run tests:
59
+
60
+ ```bash
61
+ python -m unittest discover -s tests -v
62
+ ```
63
+
64
+ ### Output
65
+
66
+ - Success: `{"found": true, "entry": {...}}`
67
+ - Card miss: `{"found": false, "error": "CARD_NOT_FOUND"}`
68
+ - Invalid upgrade input: `{"found": false, "error": "INVALID_UPGRADE_TIMES"}`
69
+ - Relic miss: `{"found": false, "error": "RELIC_NOT_FOUND"}`
70
+
71
+ ## Other Notes
72
+
73
+ Data files are shipped inside the package under `stsdb/data/`:
74
+
75
+ - `card.csv`
76
+ - `relic.csv`
77
+ - `hero.csv`
78
+ - `play.csv`
79
+ - `relic_availability.csv`
80
+ - `card_upgrade.csv`
81
+
82
+ Upgrade metadata format (`card_upgrade.csv`):
83
+
84
+ - `nameCard;hasUpgrade;costUpgraded;descriptionUpgraded`
85
+
86
+ ## Credits
87
+
88
+ This repository is adapted from the original project by [Ferdomgar97](https://github.com/ferdomgar97/Slay-the-Spire)
@@ -0,0 +1,34 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "stsdb"
7
+ version = "0.1.1"
8
+ description = "Deterministic Slay the Spire card and relic query toolset"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Taardisaa" }
14
+ ]
15
+ keywords = ["slay-the-spire", "database", "cards", "relics"]
16
+ classifiers = [
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3 :: Only",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Operating System :: OS Independent"
21
+ ]
22
+
23
+ [project.scripts]
24
+ stsdb = "stsdb.cli:main"
25
+
26
+ [tool.setuptools]
27
+ include-package-data = true
28
+
29
+ [tool.setuptools.packages.find]
30
+ where = ["."]
31
+ include = ["stsdb*"]
32
+
33
+ [tool.setuptools.package-data]
34
+ stsdb = ["data/*.csv"]
stsdb-0.1.1/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ from .core import query_card, query_relic
2
+
3
+ __all__ = ["query_card", "query_relic"]
@@ -0,0 +1,5 @@
1
+ from .cli import main
2
+
3
+
4
+ if __name__ == "__main__":
5
+ main()
@@ -0,0 +1,35 @@
1
+ import argparse
2
+ import json
3
+
4
+ from .core import query_card, query_relic
5
+
6
+
7
+ def _build_parser():
8
+ parser = argparse.ArgumentParser(description="Deterministic exact-match query toolset")
9
+ subparsers = parser.add_subparsers(dest="tool", required=True)
10
+
11
+ card_parser = subparsers.add_parser("query_card", help="Query a card by exact name")
12
+ card_parser.add_argument("name", help="Exact card name")
13
+ card_parser.add_argument(
14
+ "--upgrade-times",
15
+ type=int,
16
+ default=0,
17
+ help="Requested upgrade count (default: 0)",
18
+ )
19
+
20
+ relic_parser = subparsers.add_parser("query_relic", help="Query a relic by exact name")
21
+ relic_parser.add_argument("name", help="Exact relic name")
22
+
23
+ return parser
24
+
25
+
26
+ def main():
27
+ parser = _build_parser()
28
+ args = parser.parse_args()
29
+
30
+ if args.tool == "query_card":
31
+ result = query_card(args.name, args.upgrade_times)
32
+ else:
33
+ result = query_relic(args.name)
34
+
35
+ print(json.dumps(result, ensure_ascii=True))
@@ -0,0 +1,137 @@
1
+ import csv
2
+ from functools import lru_cache
3
+ from importlib.resources import files
4
+
5
+
6
+ def _normalize_cost(raw_cost: str):
7
+ if raw_cost == "NULL":
8
+ return None
9
+ return int(raw_cost)
10
+
11
+
12
+ def _data_path(filename: str):
13
+ return files("stsdb").joinpath("data", filename)
14
+
15
+
16
+ @lru_cache(maxsize=1)
17
+ def _cards_by_name():
18
+ cards = {}
19
+ with _data_path("card.csv").open("r", encoding="utf-8", newline="") as f:
20
+ reader = csv.reader(f, delimiter=";")
21
+ for row in reader:
22
+ name, rarity, card_type, cost, description = row
23
+ cards[name] = {
24
+ "name": name,
25
+ "rarity": None if rarity == "NULL" else rarity,
26
+ "type": card_type,
27
+ "cost": _normalize_cost(cost),
28
+ "description": description,
29
+ }
30
+ return cards
31
+
32
+
33
+ @lru_cache(maxsize=1)
34
+ def _relics_by_name():
35
+ relics = {}
36
+ with _data_path("relic.csv").open("r", encoding="utf-8", newline="") as f:
37
+ reader = csv.reader(f, delimiter=";")
38
+ for row in reader:
39
+ name, rarity, description = row
40
+ relics[name] = {
41
+ "name": name,
42
+ "rarity": rarity,
43
+ "description": description,
44
+ }
45
+ return relics
46
+
47
+
48
+ @lru_cache(maxsize=1)
49
+ def _card_playable_by():
50
+ card_map = {}
51
+ with _data_path("play.csv").open("r", encoding="utf-8", newline="") as f:
52
+ reader = csv.reader(f, delimiter=";")
53
+ for row in reader:
54
+ card_name, hero_name = row
55
+ card_map.setdefault(card_name, []).append(hero_name)
56
+ return card_map
57
+
58
+
59
+ @lru_cache(maxsize=1)
60
+ def _card_upgrade_by_name():
61
+ upgrades = {}
62
+ with _data_path("card_upgrade.csv").open("r", encoding="utf-8", newline="") as f:
63
+ reader = csv.reader(f, delimiter=";")
64
+ for row in reader:
65
+ card_name, has_upgrade, cost_upgraded, description_upgraded = row
66
+ upgrades[card_name] = {
67
+ "has_upgrade": has_upgrade == "true",
68
+ "cost_upgraded": _normalize_cost(cost_upgraded),
69
+ "description_upgraded": description_upgraded,
70
+ }
71
+ return upgrades
72
+
73
+
74
+ @lru_cache(maxsize=1)
75
+ def _relic_available_to():
76
+ relic_map = {}
77
+ with _data_path("relic_availability.csv").open("r", encoding="utf-8", newline="") as f:
78
+ reader = csv.reader(f, delimiter=";")
79
+ for row in reader:
80
+ relic_name, hero_name = row
81
+ relic_map.setdefault(relic_name, []).append(hero_name)
82
+ return relic_map
83
+
84
+
85
+ def _apply_searing_blow_upgrades(base_card, upgrade_times: int):
86
+ if upgrade_times <= 0:
87
+ return base_card
88
+
89
+ base_damage = 12
90
+ upgraded_damage = (upgrade_times * (upgrade_times + 7)) // 2 + base_damage
91
+ upgraded_description = f"Deal {upgraded_damage} damage. Can be Upgraded any number of times."
92
+
93
+ upgraded_card = dict(base_card)
94
+ upgraded_card["description"] = upgraded_description
95
+ return upgraded_card
96
+
97
+
98
+ def query_card(name: str, upgrade_times: int = 0):
99
+ if upgrade_times < 0:
100
+ return {"found": False, "error": "INVALID_UPGRADE_TIMES"}
101
+
102
+ card = _cards_by_name().get(name)
103
+ if card is None:
104
+ return {"found": False, "error": "CARD_NOT_FOUND"}
105
+
106
+ entry = dict(card)
107
+ upgrade_info = _card_upgrade_by_name().get(name)
108
+
109
+ applied_upgrade_times = 0
110
+ max_upgrade_times = 0
111
+
112
+ if name == "Searing Blow":
113
+ entry = _apply_searing_blow_upgrades(entry, upgrade_times)
114
+ applied_upgrade_times = upgrade_times
115
+ max_upgrade_times = -1
116
+ elif upgrade_info and upgrade_info["has_upgrade"]:
117
+ max_upgrade_times = 1
118
+ if upgrade_times > 0:
119
+ applied_upgrade_times = 1
120
+ entry["cost"] = upgrade_info["cost_upgraded"]
121
+ entry["description"] = upgrade_info["description_upgraded"]
122
+
123
+ entry["playable_by"] = _card_playable_by().get(name, [])
124
+ entry["requested_upgrade_times"] = upgrade_times
125
+ entry["applied_upgrade_times"] = applied_upgrade_times
126
+ entry["max_upgrade_times"] = max_upgrade_times
127
+ return {"found": True, "entry": entry}
128
+
129
+
130
+ def query_relic(name: str):
131
+ relic = _relics_by_name().get(name)
132
+ if relic is None:
133
+ return {"found": False, "error": "RELIC_NOT_FOUND"}
134
+
135
+ entry = dict(relic)
136
+ entry["available_to"] = _relic_available_to().get(name, [])
137
+ return {"found": True, "entry": entry}