fishertools 0.2.1__py3-none-any.whl → 0.4.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.
Files changed (69) hide show
  1. fishertools/__init__.py +16 -5
  2. fishertools/errors/__init__.py +11 -3
  3. fishertools/errors/exception_types.py +282 -0
  4. fishertools/errors/explainer.py +87 -1
  5. fishertools/errors/models.py +73 -1
  6. fishertools/errors/patterns.py +40 -0
  7. fishertools/examples/cli_example.py +156 -0
  8. fishertools/examples/learn_example.py +65 -0
  9. fishertools/examples/logger_example.py +176 -0
  10. fishertools/examples/menu_example.py +101 -0
  11. fishertools/examples/storage_example.py +175 -0
  12. fishertools/input_utils.py +185 -0
  13. fishertools/learn/__init__.py +19 -2
  14. fishertools/learn/examples.py +88 -1
  15. fishertools/learn/knowledge_engine.py +321 -0
  16. fishertools/learn/repl/__init__.py +19 -0
  17. fishertools/learn/repl/cli.py +31 -0
  18. fishertools/learn/repl/code_sandbox.py +229 -0
  19. fishertools/learn/repl/command_handler.py +544 -0
  20. fishertools/learn/repl/command_parser.py +165 -0
  21. fishertools/learn/repl/engine.py +479 -0
  22. fishertools/learn/repl/models.py +121 -0
  23. fishertools/learn/repl/session_manager.py +284 -0
  24. fishertools/learn/repl/test_code_sandbox.py +261 -0
  25. fishertools/learn/repl/test_code_sandbox_pbt.py +148 -0
  26. fishertools/learn/repl/test_command_handler.py +224 -0
  27. fishertools/learn/repl/test_command_handler_pbt.py +189 -0
  28. fishertools/learn/repl/test_command_parser.py +160 -0
  29. fishertools/learn/repl/test_command_parser_pbt.py +100 -0
  30. fishertools/learn/repl/test_engine.py +190 -0
  31. fishertools/learn/repl/test_session_manager.py +310 -0
  32. fishertools/learn/repl/test_session_manager_pbt.py +182 -0
  33. fishertools/learn/test_knowledge_engine.py +241 -0
  34. fishertools/learn/test_knowledge_engine_pbt.py +180 -0
  35. fishertools/patterns/__init__.py +46 -0
  36. fishertools/patterns/cli.py +175 -0
  37. fishertools/patterns/logger.py +140 -0
  38. fishertools/patterns/menu.py +99 -0
  39. fishertools/patterns/storage.py +127 -0
  40. fishertools/readme_transformer.py +631 -0
  41. fishertools/safe/__init__.py +6 -1
  42. fishertools/safe/files.py +329 -1
  43. fishertools/transform_readme.py +105 -0
  44. fishertools-0.4.0.dist-info/METADATA +104 -0
  45. fishertools-0.4.0.dist-info/RECORD +131 -0
  46. {fishertools-0.2.1.dist-info → fishertools-0.4.0.dist-info}/WHEEL +1 -1
  47. tests/test_documentation_properties.py +329 -0
  48. tests/test_documentation_structure.py +349 -0
  49. tests/test_errors/test_exception_types.py +446 -0
  50. tests/test_errors/test_exception_types_pbt.py +333 -0
  51. tests/test_errors/test_patterns.py +52 -0
  52. tests/test_input_utils/__init__.py +1 -0
  53. tests/test_input_utils/test_input_utils.py +65 -0
  54. tests/test_learn/test_examples.py +179 -1
  55. tests/test_learn/test_explain_properties.py +307 -0
  56. tests/test_patterns_cli.py +611 -0
  57. tests/test_patterns_docstrings.py +473 -0
  58. tests/test_patterns_logger.py +465 -0
  59. tests/test_patterns_menu.py +440 -0
  60. tests/test_patterns_storage.py +447 -0
  61. tests/test_readme_enhancements_v0_3_1.py +2036 -0
  62. tests/test_readme_transformer/__init__.py +1 -0
  63. tests/test_readme_transformer/test_readme_infrastructure.py +1023 -0
  64. tests/test_readme_transformer/test_transform_readme_integration.py +431 -0
  65. tests/test_safe/test_files.py +726 -1
  66. fishertools-0.2.1.dist-info/METADATA +0 -256
  67. fishertools-0.2.1.dist-info/RECORD +0 -81
  68. {fishertools-0.2.1.dist-info → fishertools-0.4.0.dist-info}/licenses/LICENSE +0 -0
  69. {fishertools-0.2.1.dist-info → fishertools-0.4.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,229 @@
1
+ """
2
+ Code sandbox for safely executing user code in the REPL.
3
+
4
+ This module provides a restricted execution environment that prevents access to
5
+ dangerous operations like file I/O, imports, and other restricted functions.
6
+ """
7
+
8
+ import sys
9
+ import io
10
+ import signal
11
+ from contextlib import redirect_stdout, redirect_stderr
12
+ from typing import Tuple, Dict, Any, Set
13
+
14
+
15
+ class CodeSandbox:
16
+ """
17
+ Safely executes Python code with restrictions and timeout support.
18
+
19
+ The sandbox prevents access to:
20
+ - File I/O operations (open, read, write)
21
+ - Module imports
22
+ - System operations (os, sys, subprocess)
23
+ - Dangerous built-in functions
24
+
25
+ Example:
26
+ >>> sandbox = CodeSandbox()
27
+ >>> success, output = sandbox.execute("print(2 + 2)")
28
+ >>> print(output)
29
+ 4
30
+ """
31
+
32
+ # Built-in functions that are allowed in the sandbox
33
+ ALLOWED_BUILTINS = {
34
+ "abs", "all", "any", "ascii", "bin", "bool", "bytearray", "bytes",
35
+ "chr", "complex", "dict", "dir", "divmod", "enumerate", "filter",
36
+ "float", "format", "frozenset", "getattr", "hasattr", "hash", "hex",
37
+ "id", "input", "int", "isinstance", "issubclass", "iter", "len",
38
+ "list", "locals", "map", "max", "min", "next", "object", "oct",
39
+ "ord", "pow", "print", "property", "range", "repr", "reversed",
40
+ "round", "set", "setattr", "slice", "sorted", "staticmethod", "str",
41
+ "sum", "super", "tuple", "type", "vars", "zip",
42
+ # Math functions
43
+ "abs", "divmod", "pow", "round",
44
+ # Type constructors
45
+ "bool", "int", "float", "complex", "str", "bytes", "bytearray",
46
+ "list", "tuple", "dict", "set", "frozenset",
47
+ # Iteration
48
+ "enumerate", "filter", "map", "reversed", "sorted", "zip",
49
+ # Other safe functions
50
+ "len", "min", "max", "sum", "all", "any",
51
+ }
52
+
53
+ # Dangerous built-in functions that should be blocked
54
+ BLOCKED_BUILTINS = {
55
+ "open", "input", "exec", "eval", "compile", "__import__",
56
+ "globals", "locals", "vars", "dir", "getattr", "setattr",
57
+ "delattr", "hasattr", "callable", "classmethod", "staticmethod",
58
+ "property", "super", "type", "object", "memoryview",
59
+ }
60
+
61
+ # Dangerous modules that cannot be imported
62
+ BLOCKED_MODULES = {
63
+ "os", "sys", "subprocess", "socket", "urllib", "requests",
64
+ "pickle", "shelve", "dbm", "sqlite3", "tempfile", "shutil",
65
+ "glob", "fnmatch", "linecache", "fileinput", "stat", "filecmp",
66
+ "pathlib", "zipfile", "tarfile", "gzip", "bz2", "lzma",
67
+ "zlib", "configparser", "netrc", "xdrlib", "plistlib",
68
+ "hashlib", "hmac", "secrets", "ssl", "asyncio", "threading",
69
+ "multiprocessing", "concurrent", "ctypes", "mmap", "select",
70
+ "selectors", "fcntl", "resource", "nis", "syslog", "grp", "pwd",
71
+ "spwd", "crypt", "termios", "tty", "pty", "fcntl", "pipes",
72
+ "posixfile", "resource", "nis", "syslog", "grp", "pwd",
73
+ }
74
+
75
+ def __init__(self, timeout: float = 5.0):
76
+ """
77
+ Initialize the code sandbox.
78
+
79
+ Args:
80
+ timeout: Maximum execution time in seconds (default: 5.0)
81
+ """
82
+ self.timeout = timeout
83
+ self.execution_count = 0
84
+
85
+ def execute(self, code: str, timeout: float = None) -> Tuple[bool, str]:
86
+ """
87
+ Execute code safely in a sandbox.
88
+
89
+ Args:
90
+ code: Python code to execute
91
+ timeout: Optional timeout override (in seconds)
92
+
93
+ Returns:
94
+ Tuple of (success, output_or_error) where:
95
+ - success: True if code executed without errors
96
+ - output_or_error: Captured output or error message
97
+
98
+ Example:
99
+ >>> sandbox = CodeSandbox()
100
+ >>> success, output = sandbox.execute("print('Hello')")
101
+ >>> print(success, output)
102
+ True Hello
103
+ """
104
+ if timeout is None:
105
+ timeout = self.timeout
106
+
107
+ # Validate code before execution
108
+ validation_error = self._validate_code(code)
109
+ if validation_error:
110
+ return False, validation_error
111
+
112
+ # Create restricted globals
113
+ restricted_globals = self._create_restricted_globals()
114
+
115
+ # Capture output
116
+ output_buffer = io.StringIO()
117
+ error_buffer = io.StringIO()
118
+
119
+ try:
120
+ # Execute code with output redirection
121
+ with redirect_stdout(output_buffer), redirect_stderr(error_buffer):
122
+ exec(code, restricted_globals)
123
+
124
+ output = output_buffer.getvalue()
125
+ return True, output
126
+
127
+ except SyntaxError as e:
128
+ error_msg = f"Syntax Error: {e.msg}"
129
+ if e.lineno:
130
+ error_msg += f" (line {e.lineno})"
131
+ return False, error_msg
132
+
133
+ except TimeoutError:
134
+ return False, "Code execution timed out. Try simpler code."
135
+
136
+ except Exception as e:
137
+ error_type = type(e).__name__
138
+ error_msg = str(e)
139
+ return False, f"{error_type}: {error_msg}"
140
+
141
+ def _validate_code(self, code: str) -> str:
142
+ """
143
+ Validate code for dangerous operations.
144
+
145
+ Args:
146
+ code: Code to validate
147
+
148
+ Returns:
149
+ Error message if validation fails, empty string if valid
150
+ """
151
+ if not code or not code.strip():
152
+ return "Code cannot be empty"
153
+
154
+ # Check for dangerous imports
155
+ dangerous_keywords = ["import ", "from ", "__import__"]
156
+ code_lower = code.lower()
157
+
158
+ for keyword in dangerous_keywords:
159
+ if keyword in code_lower:
160
+ return "Imports are not allowed in the sandbox"
161
+
162
+ # Check for file operations
163
+ file_keywords = ["open(", "read(", "write(", "file("]
164
+ for keyword in file_keywords:
165
+ if keyword in code_lower:
166
+ return "File operations are not allowed in the sandbox"
167
+
168
+ # Check for dangerous functions
169
+ dangerous_funcs = ["exec(", "eval(", "compile(", "globals(", "locals("]
170
+ for func in dangerous_funcs:
171
+ if func in code_lower:
172
+ return f"The function '{func[:-1]}' is not allowed in the sandbox"
173
+
174
+ return ""
175
+
176
+ def _create_restricted_globals(self) -> Dict[str, Any]:
177
+ """
178
+ Create a restricted globals dictionary for code execution.
179
+
180
+ Returns:
181
+ Dictionary with safe built-in functions and common modules
182
+ """
183
+ # Start with safe built-ins
184
+ safe_builtins = {
185
+ name: __builtins__[name]
186
+ for name in self.ALLOWED_BUILTINS
187
+ if name in __builtins__
188
+ }
189
+
190
+ # Add safe modules
191
+ import math
192
+ safe_modules = {
193
+ "math": math,
194
+ }
195
+
196
+ # Combine into globals
197
+ restricted_globals = {
198
+ "__builtins__": safe_builtins,
199
+ **safe_modules,
200
+ }
201
+
202
+ return restricted_globals
203
+
204
+ def get_available_builtins(self) -> list:
205
+ """
206
+ Get list of available built-in functions in the sandbox.
207
+
208
+ Returns:
209
+ Sorted list of available built-in function names
210
+ """
211
+ return sorted(self.ALLOWED_BUILTINS)
212
+
213
+ def get_blocked_builtins(self) -> list:
214
+ """
215
+ Get list of blocked built-in functions.
216
+
217
+ Returns:
218
+ Sorted list of blocked built-in function names
219
+ """
220
+ return sorted(self.BLOCKED_BUILTINS)
221
+
222
+ def get_blocked_modules(self) -> list:
223
+ """
224
+ Get list of blocked modules.
225
+
226
+ Returns:
227
+ Sorted list of blocked module names
228
+ """
229
+ return sorted(self.BLOCKED_MODULES)