dsap-cli 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.
dsap/config.py ADDED
@@ -0,0 +1,158 @@
1
+ """Configuration Management for DSAP.
2
+
3
+ Handles user preferences stored in ~/.dsap/config.json.
4
+ """
5
+
6
+ import json
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ from dsap.models import Config as ConfigModel
11
+ from dsap.models import Difficulty
12
+
13
+
14
+ class ConfigManager:
15
+ """Manages user configuration for DSAP.
16
+
17
+ Configuration is stored in ~/.dsap/config.json and includes
18
+ settings like daily goals, preferred difficulty, etc.
19
+ """
20
+
21
+ DEFAULT_PATH = Path.home() / ".dsap" / "config.json"
22
+
23
+ def __init__(self, path: Path | None = None):
24
+ """Initialize config manager.
25
+
26
+ Args:
27
+ path: Optional custom path to config file.
28
+ Defaults to ~/.dsap/config.json
29
+ """
30
+ self.path = path or self.DEFAULT_PATH
31
+ self._config: ConfigModel | None = None
32
+
33
+ def _ensure_directory(self) -> None:
34
+ """Ensure the config directory exists."""
35
+ self.path.parent.mkdir(parents=True, exist_ok=True)
36
+
37
+ def load(self) -> ConfigModel:
38
+ """Load configuration from file.
39
+
40
+ Returns default config if file doesn't exist.
41
+ """
42
+ if self._config is not None:
43
+ return self._config
44
+
45
+ if not self.path.exists():
46
+ self._config = ConfigModel()
47
+ return self._config
48
+
49
+ try:
50
+ with open(self.path, encoding="utf-8") as f:
51
+ data = json.load(f)
52
+ self._config = ConfigModel(**data)
53
+ except (json.JSONDecodeError, OSError, TypeError, ValueError):
54
+ # Invalid config file or read error, use defaults
55
+ self._config = ConfigModel()
56
+
57
+ return self._config
58
+
59
+ def save(self) -> None:
60
+ """Save current configuration to file."""
61
+ if self._config is None:
62
+ return
63
+
64
+ self._ensure_directory()
65
+
66
+ data = self._config.model_dump()
67
+
68
+ # Convert Difficulty enum to string for JSON
69
+ if data.get("preferred_difficulty"):
70
+ data["preferred_difficulty"] = data["preferred_difficulty"].value
71
+
72
+ with open(self.path, "w", encoding="utf-8") as f:
73
+ json.dump(data, f, indent=2)
74
+
75
+ def get(self, key: str) -> Any:
76
+ """Get a configuration value.
77
+
78
+ Args:
79
+ key: Configuration key
80
+
81
+ Returns:
82
+ Configuration value or None if not found
83
+ """
84
+ config = self.load()
85
+ return getattr(config, key, None)
86
+
87
+ def set(self, key: str, value: Any) -> None:
88
+ """Set a configuration value.
89
+
90
+ Args:
91
+ key: Configuration key
92
+ value: Value to set
93
+ """
94
+ config = self.load()
95
+
96
+ # Handle special cases
97
+ if key == "preferred_difficulty" and isinstance(value, str):
98
+ if value.lower() == "none":
99
+ value = None
100
+ else:
101
+ value = Difficulty.from_string(value)
102
+
103
+ if key == "preferred_set" and isinstance(value, str):
104
+ if value.lower() == "none":
105
+ value = None
106
+ # Normalize set names
107
+ elif value.lower() in ("blind75", "blind 75"):
108
+ value = "Blind 75"
109
+ elif value.lower() in ("neetcode150", "neetcode 150"):
110
+ value = "NeetCode 150"
111
+ elif value.lower() in ("grind75", "grind 75"):
112
+ value = "Grind 75"
113
+
114
+ if key == "daily_goal":
115
+ value = int(value)
116
+
117
+ if key == "show_hints":
118
+ if isinstance(value, str):
119
+ value = value.lower() in ("true", "yes", "1", "on")
120
+
121
+ if key == "auto_open_browser":
122
+ if isinstance(value, str):
123
+ value = value.lower() in ("true", "yes", "1", "on")
124
+
125
+ if hasattr(config, key):
126
+ setattr(config, key, value)
127
+ self._config = config
128
+ self.save()
129
+ else:
130
+ raise ValueError(f"Unknown configuration key: {key}")
131
+
132
+ def all(self) -> dict[str, Any]:
133
+ """Get all configuration as a dictionary."""
134
+ config = self.load()
135
+ data = config.model_dump()
136
+
137
+ # Convert enum to string for display
138
+ if data.get("preferred_difficulty"):
139
+ data["preferred_difficulty"] = data["preferred_difficulty"].value
140
+
141
+ return data
142
+
143
+ def reset(self) -> None:
144
+ """Reset configuration to defaults."""
145
+ self._config = ConfigModel()
146
+ self.save()
147
+
148
+
149
+ # Global config instance
150
+ _config_manager: ConfigManager | None = None
151
+
152
+
153
+ def get_config() -> ConfigManager:
154
+ """Get the global config manager instance."""
155
+ global _config_manager
156
+ if _config_manager is None:
157
+ _config_manager = ConfigManager()
158
+ return _config_manager
dsap/data/blind75.yaml ADDED
@@ -0,0 +1,405 @@
1
+ # Blind 75 - Essential LeetCode Problems for Coding Interviews
2
+ # Original curated list by Yangshun Tay (Tech Interview Handbook)
3
+ # https://www.teamblind.com/post/New-Year-Gift---Curated-List-of-Top-75-LeetCode-Questions-to-Save-Your-Time-OaM1orEU
4
+
5
+ metadata:
6
+ name: "Blind 75"
7
+ description: "The original 75 essential LeetCode problems for coding interviews"
8
+ source: "Tech Interview Handbook / Blind"
9
+ total_problems: 75
10
+
11
+ categories:
12
+ - name: "Array"
13
+ problems:
14
+ - title: "Two Sum"
15
+ url: "https://leetcode.com/problems/two-sum/"
16
+ difficulty: "Easy"
17
+ tags: ["array", "hash-table"]
18
+
19
+ - title: "Best Time to Buy and Sell Stock"
20
+ url: "https://leetcode.com/problems/best-time-to-buy-and-sell-stock/"
21
+ difficulty: "Easy"
22
+ tags: ["array", "dynamic-programming"]
23
+
24
+ - title: "Contains Duplicate"
25
+ url: "https://leetcode.com/problems/contains-duplicate/"
26
+ difficulty: "Easy"
27
+ tags: ["array", "hash-table"]
28
+
29
+ - title: "Product of Array Except Self"
30
+ url: "https://leetcode.com/problems/product-of-array-except-self/"
31
+ difficulty: "Medium"
32
+ tags: ["array", "prefix-sum"]
33
+
34
+ - title: "Maximum Subarray"
35
+ url: "https://leetcode.com/problems/maximum-subarray/"
36
+ difficulty: "Medium"
37
+ tags: ["array", "dynamic-programming", "divide-and-conquer"]
38
+
39
+ - title: "Maximum Product Subarray"
40
+ url: "https://leetcode.com/problems/maximum-product-subarray/"
41
+ difficulty: "Medium"
42
+ tags: ["array", "dynamic-programming"]
43
+
44
+ - title: "Find Minimum in Rotated Sorted Array"
45
+ url: "https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/"
46
+ difficulty: "Medium"
47
+ tags: ["array", "binary-search"]
48
+
49
+ - title: "Search in Rotated Sorted Array"
50
+ url: "https://leetcode.com/problems/search-in-rotated-sorted-array/"
51
+ difficulty: "Medium"
52
+ tags: ["array", "binary-search"]
53
+
54
+ - title: "3Sum"
55
+ url: "https://leetcode.com/problems/3sum/"
56
+ difficulty: "Medium"
57
+ tags: ["array", "two-pointers", "sorting"]
58
+
59
+ - title: "Container With Most Water"
60
+ url: "https://leetcode.com/problems/container-with-most-water/"
61
+ difficulty: "Medium"
62
+ tags: ["array", "two-pointers", "greedy"]
63
+
64
+ - name: "Binary"
65
+ problems:
66
+ - title: "Sum of Two Integers"
67
+ url: "https://leetcode.com/problems/sum-of-two-integers/"
68
+ difficulty: "Medium"
69
+ tags: ["bit-manipulation"]
70
+
71
+ - title: "Number of 1 Bits"
72
+ url: "https://leetcode.com/problems/number-of-1-bits/"
73
+ difficulty: "Easy"
74
+ tags: ["bit-manipulation"]
75
+
76
+ - title: "Counting Bits"
77
+ url: "https://leetcode.com/problems/counting-bits/"
78
+ difficulty: "Easy"
79
+ tags: ["bit-manipulation", "dynamic-programming"]
80
+
81
+ - title: "Missing Number"
82
+ url: "https://leetcode.com/problems/missing-number/"
83
+ difficulty: "Easy"
84
+ tags: ["array", "bit-manipulation"]
85
+
86
+ - title: "Reverse Bits"
87
+ url: "https://leetcode.com/problems/reverse-bits/"
88
+ difficulty: "Easy"
89
+ tags: ["bit-manipulation"]
90
+
91
+ - name: "Dynamic Programming"
92
+ problems:
93
+ - title: "Climbing Stairs"
94
+ url: "https://leetcode.com/problems/climbing-stairs/"
95
+ difficulty: "Easy"
96
+ tags: ["dynamic-programming"]
97
+
98
+ - title: "Coin Change"
99
+ url: "https://leetcode.com/problems/coin-change/"
100
+ difficulty: "Medium"
101
+ tags: ["dynamic-programming", "bfs"]
102
+
103
+ - title: "Longest Increasing Subsequence"
104
+ url: "https://leetcode.com/problems/longest-increasing-subsequence/"
105
+ difficulty: "Medium"
106
+ tags: ["dynamic-programming", "binary-search"]
107
+
108
+ - title: "Longest Common Subsequence"
109
+ url: "https://leetcode.com/problems/longest-common-subsequence/"
110
+ difficulty: "Medium"
111
+ tags: ["dynamic-programming"]
112
+
113
+ - title: "Word Break"
114
+ url: "https://leetcode.com/problems/word-break/"
115
+ difficulty: "Medium"
116
+ tags: ["dynamic-programming", "trie", "memoization"]
117
+
118
+ - title: "Combination Sum IV"
119
+ url: "https://leetcode.com/problems/combination-sum-iv/"
120
+ difficulty: "Medium"
121
+ tags: ["dynamic-programming"]
122
+
123
+ - title: "House Robber"
124
+ url: "https://leetcode.com/problems/house-robber/"
125
+ difficulty: "Medium"
126
+ tags: ["dynamic-programming"]
127
+
128
+ - title: "House Robber II"
129
+ url: "https://leetcode.com/problems/house-robber-ii/"
130
+ difficulty: "Medium"
131
+ tags: ["dynamic-programming"]
132
+
133
+ - title: "Decode Ways"
134
+ url: "https://leetcode.com/problems/decode-ways/"
135
+ difficulty: "Medium"
136
+ tags: ["dynamic-programming", "string"]
137
+
138
+ - title: "Unique Paths"
139
+ url: "https://leetcode.com/problems/unique-paths/"
140
+ difficulty: "Medium"
141
+ tags: ["dynamic-programming", "math"]
142
+
143
+ - title: "Jump Game"
144
+ url: "https://leetcode.com/problems/jump-game/"
145
+ difficulty: "Medium"
146
+ tags: ["dynamic-programming", "greedy"]
147
+
148
+ - name: "Graph"
149
+ problems:
150
+ - title: "Clone Graph"
151
+ url: "https://leetcode.com/problems/clone-graph/"
152
+ difficulty: "Medium"
153
+ tags: ["graph", "bfs", "dfs"]
154
+
155
+ - title: "Course Schedule"
156
+ url: "https://leetcode.com/problems/course-schedule/"
157
+ difficulty: "Medium"
158
+ tags: ["graph", "topological-sort", "dfs"]
159
+
160
+ - title: "Pacific Atlantic Water Flow"
161
+ url: "https://leetcode.com/problems/pacific-atlantic-water-flow/"
162
+ difficulty: "Medium"
163
+ tags: ["graph", "dfs", "bfs"]
164
+
165
+ - title: "Number of Islands"
166
+ url: "https://leetcode.com/problems/number-of-islands/"
167
+ difficulty: "Medium"
168
+ tags: ["graph", "dfs", "bfs", "union-find"]
169
+
170
+ - title: "Longest Consecutive Sequence"
171
+ url: "https://leetcode.com/problems/longest-consecutive-sequence/"
172
+ difficulty: "Medium"
173
+ tags: ["array", "hash-table", "union-find"]
174
+
175
+ - title: "Alien Dictionary"
176
+ url: "https://leetcode.com/problems/alien-dictionary/"
177
+ difficulty: "Hard"
178
+ tags: ["graph", "topological-sort"]
179
+
180
+ - title: "Graph Valid Tree"
181
+ url: "https://leetcode.com/problems/graph-valid-tree/"
182
+ difficulty: "Medium"
183
+ tags: ["graph", "dfs", "bfs", "union-find"]
184
+
185
+ - title: "Number of Connected Components in an Undirected Graph"
186
+ url: "https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/"
187
+ difficulty: "Medium"
188
+ tags: ["graph", "dfs", "bfs", "union-find"]
189
+
190
+ - name: "Interval"
191
+ problems:
192
+ - title: "Insert Interval"
193
+ url: "https://leetcode.com/problems/insert-interval/"
194
+ difficulty: "Medium"
195
+ tags: ["array", "interval"]
196
+
197
+ - title: "Merge Intervals"
198
+ url: "https://leetcode.com/problems/merge-intervals/"
199
+ difficulty: "Medium"
200
+ tags: ["array", "interval", "sorting"]
201
+
202
+ - title: "Non-overlapping Intervals"
203
+ url: "https://leetcode.com/problems/non-overlapping-intervals/"
204
+ difficulty: "Medium"
205
+ tags: ["array", "interval", "greedy", "sorting"]
206
+
207
+ - title: "Meeting Rooms"
208
+ url: "https://leetcode.com/problems/meeting-rooms/"
209
+ difficulty: "Easy"
210
+ tags: ["array", "interval", "sorting"]
211
+
212
+ - title: "Meeting Rooms II"
213
+ url: "https://leetcode.com/problems/meeting-rooms-ii/"
214
+ difficulty: "Medium"
215
+ tags: ["array", "interval", "heap", "sorting"]
216
+
217
+ - name: "Linked List"
218
+ problems:
219
+ - title: "Reverse Linked List"
220
+ url: "https://leetcode.com/problems/reverse-linked-list/"
221
+ difficulty: "Easy"
222
+ tags: ["linked-list"]
223
+
224
+ - title: "Linked List Cycle"
225
+ url: "https://leetcode.com/problems/linked-list-cycle/"
226
+ difficulty: "Easy"
227
+ tags: ["linked-list", "two-pointers"]
228
+
229
+ - title: "Merge Two Sorted Lists"
230
+ url: "https://leetcode.com/problems/merge-two-sorted-lists/"
231
+ difficulty: "Easy"
232
+ tags: ["linked-list", "recursion"]
233
+
234
+ - title: "Merge K Sorted Lists"
235
+ url: "https://leetcode.com/problems/merge-k-sorted-lists/"
236
+ difficulty: "Hard"
237
+ tags: ["linked-list", "heap", "divide-and-conquer"]
238
+
239
+ - title: "Remove Nth Node From End of List"
240
+ url: "https://leetcode.com/problems/remove-nth-node-from-end-of-list/"
241
+ difficulty: "Medium"
242
+ tags: ["linked-list", "two-pointers"]
243
+
244
+ - title: "Reorder List"
245
+ url: "https://leetcode.com/problems/reorder-list/"
246
+ difficulty: "Medium"
247
+ tags: ["linked-list", "two-pointers", "stack"]
248
+
249
+ - name: "Matrix"
250
+ problems:
251
+ - title: "Set Matrix Zeroes"
252
+ url: "https://leetcode.com/problems/set-matrix-zeroes/"
253
+ difficulty: "Medium"
254
+ tags: ["array", "matrix"]
255
+
256
+ - title: "Spiral Matrix"
257
+ url: "https://leetcode.com/problems/spiral-matrix/"
258
+ difficulty: "Medium"
259
+ tags: ["array", "matrix"]
260
+
261
+ - title: "Rotate Image"
262
+ url: "https://leetcode.com/problems/rotate-image/"
263
+ difficulty: "Medium"
264
+ tags: ["array", "matrix"]
265
+
266
+ - title: "Word Search"
267
+ url: "https://leetcode.com/problems/word-search/"
268
+ difficulty: "Medium"
269
+ tags: ["array", "matrix", "backtracking"]
270
+
271
+ - name: "String"
272
+ problems:
273
+ - title: "Longest Substring Without Repeating Characters"
274
+ url: "https://leetcode.com/problems/longest-substring-without-repeating-characters/"
275
+ difficulty: "Medium"
276
+ tags: ["string", "sliding-window", "hash-table"]
277
+
278
+ - title: "Longest Repeating Character Replacement"
279
+ url: "https://leetcode.com/problems/longest-repeating-character-replacement/"
280
+ difficulty: "Medium"
281
+ tags: ["string", "sliding-window"]
282
+
283
+ - title: "Minimum Window Substring"
284
+ url: "https://leetcode.com/problems/minimum-window-substring/"
285
+ difficulty: "Hard"
286
+ tags: ["string", "sliding-window", "hash-table"]
287
+
288
+ - title: "Valid Anagram"
289
+ url: "https://leetcode.com/problems/valid-anagram/"
290
+ difficulty: "Easy"
291
+ tags: ["string", "hash-table", "sorting"]
292
+
293
+ - title: "Group Anagrams"
294
+ url: "https://leetcode.com/problems/group-anagrams/"
295
+ difficulty: "Medium"
296
+ tags: ["string", "hash-table", "sorting"]
297
+
298
+ - title: "Valid Parentheses"
299
+ url: "https://leetcode.com/problems/valid-parentheses/"
300
+ difficulty: "Easy"
301
+ tags: ["string", "stack"]
302
+
303
+ - title: "Valid Palindrome"
304
+ url: "https://leetcode.com/problems/valid-palindrome/"
305
+ difficulty: "Easy"
306
+ tags: ["string", "two-pointers"]
307
+
308
+ - title: "Longest Palindromic Substring"
309
+ url: "https://leetcode.com/problems/longest-palindromic-substring/"
310
+ difficulty: "Medium"
311
+ tags: ["string", "dynamic-programming"]
312
+
313
+ - title: "Palindromic Substrings"
314
+ url: "https://leetcode.com/problems/palindromic-substrings/"
315
+ difficulty: "Medium"
316
+ tags: ["string", "dynamic-programming"]
317
+
318
+ - title: "Encode and Decode Strings"
319
+ url: "https://leetcode.com/problems/encode-and-decode-strings/"
320
+ difficulty: "Medium"
321
+ tags: ["string", "design"]
322
+
323
+ - name: "Tree"
324
+ problems:
325
+ - title: "Maximum Depth of Binary Tree"
326
+ url: "https://leetcode.com/problems/maximum-depth-of-binary-tree/"
327
+ difficulty: "Easy"
328
+ tags: ["tree", "dfs", "bfs"]
329
+
330
+ - title: "Same Tree"
331
+ url: "https://leetcode.com/problems/same-tree/"
332
+ difficulty: "Easy"
333
+ tags: ["tree", "dfs", "bfs"]
334
+
335
+ - title: "Invert Binary Tree"
336
+ url: "https://leetcode.com/problems/invert-binary-tree/"
337
+ difficulty: "Easy"
338
+ tags: ["tree", "dfs", "bfs"]
339
+
340
+ - title: "Binary Tree Maximum Path Sum"
341
+ url: "https://leetcode.com/problems/binary-tree-maximum-path-sum/"
342
+ difficulty: "Hard"
343
+ tags: ["tree", "dfs", "dynamic-programming"]
344
+
345
+ - title: "Binary Tree Level Order Traversal"
346
+ url: "https://leetcode.com/problems/binary-tree-level-order-traversal/"
347
+ difficulty: "Medium"
348
+ tags: ["tree", "bfs"]
349
+
350
+ - title: "Serialize and Deserialize Binary Tree"
351
+ url: "https://leetcode.com/problems/serialize-and-deserialize-binary-tree/"
352
+ difficulty: "Hard"
353
+ tags: ["tree", "dfs", "bfs", "design"]
354
+
355
+ - title: "Subtree of Another Tree"
356
+ url: "https://leetcode.com/problems/subtree-of-another-tree/"
357
+ difficulty: "Easy"
358
+ tags: ["tree", "dfs"]
359
+
360
+ - title: "Construct Binary Tree from Preorder and Inorder Traversal"
361
+ url: "https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/"
362
+ difficulty: "Medium"
363
+ tags: ["tree", "dfs", "array"]
364
+
365
+ - title: "Validate Binary Search Tree"
366
+ url: "https://leetcode.com/problems/validate-binary-search-tree/"
367
+ difficulty: "Medium"
368
+ tags: ["tree", "dfs", "bst"]
369
+
370
+ - title: "Kth Smallest Element in a BST"
371
+ url: "https://leetcode.com/problems/kth-smallest-element-in-a-bst/"
372
+ difficulty: "Medium"
373
+ tags: ["tree", "dfs", "bst"]
374
+
375
+ - title: "Lowest Common Ancestor of a Binary Search Tree"
376
+ url: "https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/"
377
+ difficulty: "Medium"
378
+ tags: ["tree", "dfs", "bst"]
379
+
380
+ - title: "Implement Trie (Prefix Tree)"
381
+ url: "https://leetcode.com/problems/implement-trie-prefix-tree/"
382
+ difficulty: "Medium"
383
+ tags: ["trie", "design"]
384
+
385
+ - title: "Add and Search Word"
386
+ url: "https://leetcode.com/problems/design-add-and-search-words-data-structure/"
387
+ difficulty: "Medium"
388
+ tags: ["trie", "dfs", "design"]
389
+
390
+ - title: "Word Search II"
391
+ url: "https://leetcode.com/problems/word-search-ii/"
392
+ difficulty: "Hard"
393
+ tags: ["trie", "backtracking", "matrix"]
394
+
395
+ - name: "Heap"
396
+ problems:
397
+ - title: "Top K Frequent Elements"
398
+ url: "https://leetcode.com/problems/top-k-frequent-elements/"
399
+ difficulty: "Medium"
400
+ tags: ["array", "hash-table", "heap"]
401
+
402
+ - title: "Find Median from Data Stream"
403
+ url: "https://leetcode.com/problems/find-median-from-data-stream/"
404
+ difficulty: "Hard"
405
+ tags: ["heap", "design", "sorting"]