zexus 1.6.2
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.
- package/LICENSE +0 -0
- package/README.md +2513 -0
- package/bin/zexus +2 -0
- package/bin/zpics +2 -0
- package/bin/zpm +2 -0
- package/bin/zx +2 -0
- package/bin/zx-deploy +2 -0
- package/bin/zx-dev +2 -0
- package/bin/zx-run +2 -0
- package/package.json +66 -0
- package/scripts/README.md +24 -0
- package/scripts/postinstall.js +44 -0
- package/shared_config.json +24 -0
- package/src/README.md +1525 -0
- package/src/tests/run_zexus_tests.py +117 -0
- package/src/tests/test_all_phases.zx +346 -0
- package/src/tests/test_blockchain_features.zx +306 -0
- package/src/tests/test_complexity_features.zx +321 -0
- package/src/tests/test_core_integration.py +185 -0
- package/src/tests/test_phase10_ecosystem.zx +177 -0
- package/src/tests/test_phase1_modifiers.zx +87 -0
- package/src/tests/test_phase2_plugins.zx +80 -0
- package/src/tests/test_phase3_security.zx +97 -0
- package/src/tests/test_phase4_vfs.zx +116 -0
- package/src/tests/test_phase5_types.zx +117 -0
- package/src/tests/test_phase6_metaprogramming.zx +125 -0
- package/src/tests/test_phase7_optimization.zx +132 -0
- package/src/tests/test_phase9_advanced_types.zx +157 -0
- package/src/tests/test_security_features.py +419 -0
- package/src/tests/test_security_features.zx +276 -0
- package/src/tests/test_simple_zx.zx +1 -0
- package/src/tests/test_verification_simple.zx +69 -0
- package/src/zexus/__init__.py +28 -0
- package/src/zexus/__main__.py +5 -0
- package/src/zexus/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/advanced_types.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/builtin_modules.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/capability_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/complexity_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/concurrency_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/config.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/dependency_injection.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/ecosystem.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/environment.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/error_reporter.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/hybrid_orchestrator.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/metaprogramming.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/module_cache.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/object.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/optimization.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/plugin_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/policy_engine.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/security.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/stdlib_integration.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/strategy_recovery.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/syntax_validator.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/type_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/virtual_filesystem.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_token.cpython-312.pyc +0 -0
- package/src/zexus/advanced_types.py +401 -0
- package/src/zexus/blockchain/__init__.py +40 -0
- package/src/zexus/blockchain/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/crypto.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/ledger.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/transaction.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/crypto.py +463 -0
- package/src/zexus/blockchain/ledger.py +255 -0
- package/src/zexus/blockchain/transaction.py +267 -0
- package/src/zexus/builtin_modules.py +284 -0
- package/src/zexus/builtin_plugins.py +317 -0
- package/src/zexus/capability_system.py +372 -0
- package/src/zexus/cli/__init__.py +2 -0
- package/src/zexus/cli/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/cli/__pycache__/main.cpython-312.pyc +0 -0
- package/src/zexus/cli/main.py +707 -0
- package/src/zexus/cli/zpm.py +203 -0
- package/src/zexus/compare_interpreter_compiler.py +146 -0
- package/src/zexus/compiler/__init__.py +169 -0
- package/src/zexus/compiler/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/compiler/bytecode.py +266 -0
- package/src/zexus/compiler/compat_runtime.py +277 -0
- package/src/zexus/compiler/lexer.py +257 -0
- package/src/zexus/compiler/parser.py +779 -0
- package/src/zexus/compiler/semantic.py +118 -0
- package/src/zexus/compiler/zexus_ast.py +454 -0
- package/src/zexus/complexity_system.py +575 -0
- package/src/zexus/concurrency_system.py +493 -0
- package/src/zexus/config.py +201 -0
- package/src/zexus/crypto_bridge.py +19 -0
- package/src/zexus/dependency_injection.py +423 -0
- package/src/zexus/ecosystem.py +434 -0
- package/src/zexus/environment.py +101 -0
- package/src/zexus/environment_manager.py +119 -0
- package/src/zexus/error_reporter.py +314 -0
- package/src/zexus/evaluator/__init__.py +12 -0
- package/src/zexus/evaluator/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/bytecode_compiler.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/core.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/expressions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/functions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/integration.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/bytecode_compiler.py +700 -0
- package/src/zexus/evaluator/core.py +891 -0
- package/src/zexus/evaluator/expressions.py +827 -0
- package/src/zexus/evaluator/functions.py +3989 -0
- package/src/zexus/evaluator/integration.py +396 -0
- package/src/zexus/evaluator/statements.py +4303 -0
- package/src/zexus/evaluator/utils.py +126 -0
- package/src/zexus/evaluator_original.py +2041 -0
- package/src/zexus/external_bridge.py +16 -0
- package/src/zexus/find_affected_imports.sh +155 -0
- package/src/zexus/hybrid_orchestrator.py +152 -0
- package/src/zexus/input_validation.py +259 -0
- package/src/zexus/lexer.py +571 -0
- package/src/zexus/logging.py +89 -0
- package/src/zexus/lsp/__init__.py +9 -0
- package/src/zexus/lsp/completion_provider.py +207 -0
- package/src/zexus/lsp/definition_provider.py +22 -0
- package/src/zexus/lsp/hover_provider.py +71 -0
- package/src/zexus/lsp/server.py +269 -0
- package/src/zexus/lsp/symbol_provider.py +31 -0
- package/src/zexus/metaprogramming.py +321 -0
- package/src/zexus/module_cache.py +89 -0
- package/src/zexus/module_manager.py +107 -0
- package/src/zexus/object.py +973 -0
- package/src/zexus/optimization.py +424 -0
- package/src/zexus/parser/__init__.py +31 -0
- package/src/zexus/parser/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_context.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_structural.cpython-312.pyc +0 -0
- package/src/zexus/parser/integration.py +86 -0
- package/src/zexus/parser/parser.py +3977 -0
- package/src/zexus/parser/strategy_context.py +7254 -0
- package/src/zexus/parser/strategy_structural.py +1033 -0
- package/src/zexus/persistence.py +391 -0
- package/src/zexus/plugin_system.py +290 -0
- package/src/zexus/policy_engine.py +365 -0
- package/src/zexus/profiler/__init__.py +5 -0
- package/src/zexus/profiler/profiler.py +233 -0
- package/src/zexus/purity_system.py +398 -0
- package/src/zexus/runtime/__init__.py +20 -0
- package/src/zexus/runtime/async_runtime.py +324 -0
- package/src/zexus/search_old_imports.sh +65 -0
- package/src/zexus/security.py +1407 -0
- package/src/zexus/stack_trace.py +233 -0
- package/src/zexus/stdlib/__init__.py +27 -0
- package/src/zexus/stdlib/blockchain.py +341 -0
- package/src/zexus/stdlib/compression.py +167 -0
- package/src/zexus/stdlib/crypto.py +124 -0
- package/src/zexus/stdlib/datetime.py +163 -0
- package/src/zexus/stdlib/db_mongo.py +199 -0
- package/src/zexus/stdlib/db_mysql.py +162 -0
- package/src/zexus/stdlib/db_postgres.py +163 -0
- package/src/zexus/stdlib/db_sqlite.py +133 -0
- package/src/zexus/stdlib/encoding.py +230 -0
- package/src/zexus/stdlib/fs.py +195 -0
- package/src/zexus/stdlib/http.py +219 -0
- package/src/zexus/stdlib/http_server.py +248 -0
- package/src/zexus/stdlib/json_module.py +61 -0
- package/src/zexus/stdlib/math.py +360 -0
- package/src/zexus/stdlib/os_module.py +265 -0
- package/src/zexus/stdlib/regex.py +148 -0
- package/src/zexus/stdlib/sockets.py +253 -0
- package/src/zexus/stdlib/test_framework.zx +208 -0
- package/src/zexus/stdlib/test_runner.zx +119 -0
- package/src/zexus/stdlib_integration.py +341 -0
- package/src/zexus/strategy_recovery.py +256 -0
- package/src/zexus/syntax_validator.py +356 -0
- package/src/zexus/testing/zpics.py +407 -0
- package/src/zexus/testing/zpics_runtime.py +369 -0
- package/src/zexus/type_system.py +374 -0
- package/src/zexus/validation_system.py +569 -0
- package/src/zexus/virtual_filesystem.py +355 -0
- package/src/zexus/vm/__init__.py +8 -0
- package/src/zexus/vm/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/async_optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/bytecode.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/memory_manager.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/memory_pool.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/peephole_optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/profiler.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/register_allocator.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/register_vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/ssa_converter.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/async_optimizer.py +420 -0
- package/src/zexus/vm/bytecode.py +428 -0
- package/src/zexus/vm/bytecode_converter.py +297 -0
- package/src/zexus/vm/cache.py +532 -0
- package/src/zexus/vm/jit.py +720 -0
- package/src/zexus/vm/memory_manager.py +520 -0
- package/src/zexus/vm/memory_pool.py +511 -0
- package/src/zexus/vm/optimizer.py +478 -0
- package/src/zexus/vm/parallel_vm.py +899 -0
- package/src/zexus/vm/peephole_optimizer.py +452 -0
- package/src/zexus/vm/profiler.py +527 -0
- package/src/zexus/vm/register_allocator.py +462 -0
- package/src/zexus/vm/register_vm.py +520 -0
- package/src/zexus/vm/ssa_converter.py +757 -0
- package/src/zexus/vm/vm.py +1392 -0
- package/src/zexus/zexus_ast.py +1782 -0
- package/src/zexus/zexus_token.py +253 -0
- package/src/zexus/zpm/__init__.py +15 -0
- package/src/zexus/zpm/installer.py +116 -0
- package/src/zexus/zpm/package_manager.py +208 -0
- package/src/zexus/zpm/publisher.py +98 -0
- package/src/zexus/zpm/registry.py +110 -0
- package/src/zexus.egg-info/PKG-INFO +2235 -0
- package/src/zexus.egg-info/SOURCES.txt +876 -0
- package/src/zexus.egg-info/dependency_links.txt +1 -0
- package/src/zexus.egg-info/entry_points.txt +3 -0
- package/src/zexus.egg-info/not-zip-safe +1 -0
- package/src/zexus.egg-info/requires.txt +14 -0
- package/src/zexus.egg-info/top_level.txt +2 -0
- package/zexus.json +14 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"""File System module for Zexus standard library."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import shutil
|
|
5
|
+
import glob as glob_module
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import List, Dict, Any
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class FileSystemModule:
|
|
11
|
+
"""Provides file system operations."""
|
|
12
|
+
|
|
13
|
+
@staticmethod
|
|
14
|
+
def read_file(path: str, encoding: str = 'utf-8') -> str:
|
|
15
|
+
"""Read entire file as text."""
|
|
16
|
+
with open(path, 'r', encoding=encoding) as f:
|
|
17
|
+
return f.read()
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def write_file(path: str, content: str, encoding: str = 'utf-8') -> None:
|
|
21
|
+
"""Write text to file."""
|
|
22
|
+
# Create parent directory if it doesn't exist
|
|
23
|
+
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
|
24
|
+
with open(path, 'w', encoding=encoding) as f:
|
|
25
|
+
f.write(content)
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def append_file(path: str, content: str, encoding: str = 'utf-8') -> None:
|
|
29
|
+
"""Append text to file."""
|
|
30
|
+
# Create parent directory if it doesn't exist (for consistency with write_file)
|
|
31
|
+
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
|
32
|
+
with open(path, 'a', encoding=encoding) as f:
|
|
33
|
+
f.write(content)
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def read_binary(path: str) -> bytes:
|
|
37
|
+
"""Read file as binary."""
|
|
38
|
+
with open(path, 'rb') as f:
|
|
39
|
+
return f.read()
|
|
40
|
+
|
|
41
|
+
@staticmethod
|
|
42
|
+
def write_binary(path: str, data: bytes) -> None:
|
|
43
|
+
"""Write binary data to file."""
|
|
44
|
+
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
|
45
|
+
with open(path, 'wb') as f:
|
|
46
|
+
f.write(data)
|
|
47
|
+
|
|
48
|
+
@staticmethod
|
|
49
|
+
def exists(path: str) -> bool:
|
|
50
|
+
"""Check if file or directory exists."""
|
|
51
|
+
return os.path.exists(path)
|
|
52
|
+
|
|
53
|
+
@staticmethod
|
|
54
|
+
def is_file(path: str) -> bool:
|
|
55
|
+
"""Check if path is a file."""
|
|
56
|
+
return os.path.isfile(path)
|
|
57
|
+
|
|
58
|
+
@staticmethod
|
|
59
|
+
def is_dir(path: str) -> bool:
|
|
60
|
+
"""Check if path is a directory."""
|
|
61
|
+
return os.path.isdir(path)
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
def mkdir(path: str, parents: bool = True) -> None:
|
|
65
|
+
"""Create directory."""
|
|
66
|
+
Path(path).mkdir(parents=parents, exist_ok=True)
|
|
67
|
+
|
|
68
|
+
@staticmethod
|
|
69
|
+
def rmdir(path: str, recursive: bool = False) -> None:
|
|
70
|
+
"""Remove directory."""
|
|
71
|
+
if recursive:
|
|
72
|
+
shutil.rmtree(path)
|
|
73
|
+
else:
|
|
74
|
+
os.rmdir(path)
|
|
75
|
+
|
|
76
|
+
@staticmethod
|
|
77
|
+
def remove(path: str) -> None:
|
|
78
|
+
"""Remove file."""
|
|
79
|
+
os.remove(path)
|
|
80
|
+
|
|
81
|
+
@staticmethod
|
|
82
|
+
def rename(old_path: str, new_path: str) -> None:
|
|
83
|
+
"""Rename/move file or directory."""
|
|
84
|
+
os.rename(old_path, new_path)
|
|
85
|
+
|
|
86
|
+
@staticmethod
|
|
87
|
+
def copy_file(src: str, dst: str) -> None:
|
|
88
|
+
"""Copy file."""
|
|
89
|
+
shutil.copy2(src, dst)
|
|
90
|
+
|
|
91
|
+
@staticmethod
|
|
92
|
+
def copy_dir(src: str, dst: str) -> None:
|
|
93
|
+
"""Copy directory recursively."""
|
|
94
|
+
shutil.copytree(src, dst)
|
|
95
|
+
|
|
96
|
+
@staticmethod
|
|
97
|
+
def list_dir(path: str = '.') -> List[str]:
|
|
98
|
+
"""List directory contents."""
|
|
99
|
+
return os.listdir(path)
|
|
100
|
+
|
|
101
|
+
@staticmethod
|
|
102
|
+
def walk(path: str) -> List[Dict[str, Any]]:
|
|
103
|
+
"""Walk directory tree."""
|
|
104
|
+
result = []
|
|
105
|
+
for root, dirs, files in os.walk(path):
|
|
106
|
+
result.append({
|
|
107
|
+
'root': root,
|
|
108
|
+
'dirs': dirs,
|
|
109
|
+
'files': files
|
|
110
|
+
})
|
|
111
|
+
return result
|
|
112
|
+
|
|
113
|
+
@staticmethod
|
|
114
|
+
def glob(pattern: str, recursive: bool = False) -> List[str]:
|
|
115
|
+
"""Find files matching pattern."""
|
|
116
|
+
return glob_module.glob(pattern, recursive=recursive)
|
|
117
|
+
|
|
118
|
+
@staticmethod
|
|
119
|
+
def get_size(path: str) -> int:
|
|
120
|
+
"""Get file size in bytes."""
|
|
121
|
+
return os.path.getsize(path)
|
|
122
|
+
|
|
123
|
+
@staticmethod
|
|
124
|
+
def get_cwd() -> str:
|
|
125
|
+
"""Get current working directory."""
|
|
126
|
+
return os.getcwd()
|
|
127
|
+
|
|
128
|
+
@staticmethod
|
|
129
|
+
def chdir(path: str) -> None:
|
|
130
|
+
"""Change current working directory."""
|
|
131
|
+
os.chdir(path)
|
|
132
|
+
|
|
133
|
+
@staticmethod
|
|
134
|
+
def abs_path(path: str) -> str:
|
|
135
|
+
"""Get absolute path."""
|
|
136
|
+
return os.path.abspath(path)
|
|
137
|
+
|
|
138
|
+
@staticmethod
|
|
139
|
+
def join(*paths: str) -> str:
|
|
140
|
+
"""Join path components."""
|
|
141
|
+
return os.path.join(*paths)
|
|
142
|
+
|
|
143
|
+
@staticmethod
|
|
144
|
+
def basename(path: str) -> str:
|
|
145
|
+
"""Get file name from path."""
|
|
146
|
+
return os.path.basename(path)
|
|
147
|
+
|
|
148
|
+
@staticmethod
|
|
149
|
+
def dirname(path: str) -> str:
|
|
150
|
+
"""Get directory name from path."""
|
|
151
|
+
return os.path.dirname(path)
|
|
152
|
+
|
|
153
|
+
@staticmethod
|
|
154
|
+
def splitext(path: str) -> tuple:
|
|
155
|
+
"""Split file extension."""
|
|
156
|
+
return os.path.splitext(path)
|
|
157
|
+
|
|
158
|
+
@staticmethod
|
|
159
|
+
def get_stat(path: str) -> Dict[str, Any]:
|
|
160
|
+
"""Get file statistics."""
|
|
161
|
+
stat = os.stat(path)
|
|
162
|
+
return {
|
|
163
|
+
'size': stat.st_size,
|
|
164
|
+
'atime': stat.st_atime,
|
|
165
|
+
'mtime': stat.st_mtime,
|
|
166
|
+
'ctime': stat.st_ctime,
|
|
167
|
+
'mode': stat.st_mode,
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
# Export functions for easy access
|
|
172
|
+
read_file = FileSystemModule.read_file
|
|
173
|
+
write_file = FileSystemModule.write_file
|
|
174
|
+
append_file = FileSystemModule.append_file
|
|
175
|
+
exists = FileSystemModule.exists
|
|
176
|
+
is_file = FileSystemModule.is_file
|
|
177
|
+
is_dir = FileSystemModule.is_dir
|
|
178
|
+
mkdir = FileSystemModule.mkdir
|
|
179
|
+
rmdir = FileSystemModule.rmdir
|
|
180
|
+
remove = FileSystemModule.remove
|
|
181
|
+
rename = FileSystemModule.rename
|
|
182
|
+
copy_file = FileSystemModule.copy_file
|
|
183
|
+
copy_dir = FileSystemModule.copy_dir
|
|
184
|
+
list_dir = FileSystemModule.list_dir
|
|
185
|
+
walk = FileSystemModule.walk
|
|
186
|
+
glob = FileSystemModule.glob
|
|
187
|
+
get_size = FileSystemModule.get_size
|
|
188
|
+
get_cwd = FileSystemModule.get_cwd
|
|
189
|
+
chdir = FileSystemModule.chdir
|
|
190
|
+
abs_path = FileSystemModule.abs_path
|
|
191
|
+
join = FileSystemModule.join
|
|
192
|
+
basename = FileSystemModule.basename
|
|
193
|
+
dirname = FileSystemModule.dirname
|
|
194
|
+
splitext = FileSystemModule.splitext
|
|
195
|
+
get_stat = FileSystemModule.get_stat
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"""HTTP module for Zexus standard library."""
|
|
2
|
+
|
|
3
|
+
import urllib.request
|
|
4
|
+
import urllib.parse
|
|
5
|
+
import urllib.error
|
|
6
|
+
import json as json_lib
|
|
7
|
+
from typing import Dict, Any, Optional
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class HttpModule:
|
|
11
|
+
"""Provides HTTP client operations."""
|
|
12
|
+
|
|
13
|
+
@staticmethod
|
|
14
|
+
def get(url: str, headers: Optional[Dict[str, str]] = None, timeout: int = 30) -> Dict[str, Any]:
|
|
15
|
+
"""Make HTTP GET request."""
|
|
16
|
+
if headers is None:
|
|
17
|
+
headers = {}
|
|
18
|
+
|
|
19
|
+
req = urllib.request.Request(url, headers=headers, method='GET')
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
with urllib.request.urlopen(req, timeout=timeout) as response:
|
|
23
|
+
body = response.read().decode('utf-8')
|
|
24
|
+
return {
|
|
25
|
+
'status': response.status,
|
|
26
|
+
'headers': dict(response.headers),
|
|
27
|
+
'body': body
|
|
28
|
+
}
|
|
29
|
+
except urllib.error.HTTPError as e:
|
|
30
|
+
try:
|
|
31
|
+
error_body = e.read().decode('utf-8')
|
|
32
|
+
except UnicodeDecodeError:
|
|
33
|
+
error_body = e.read().decode('utf-8', errors='replace')
|
|
34
|
+
return {
|
|
35
|
+
'status': e.code,
|
|
36
|
+
'headers': dict(e.headers),
|
|
37
|
+
'body': error_body,
|
|
38
|
+
'error': str(e)
|
|
39
|
+
}
|
|
40
|
+
except Exception as e:
|
|
41
|
+
return {
|
|
42
|
+
'status': 0,
|
|
43
|
+
'headers': {},
|
|
44
|
+
'body': '',
|
|
45
|
+
'error': str(e)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@staticmethod
|
|
49
|
+
def post(url: str, data: Any = None, headers: Optional[Dict[str, str]] = None,
|
|
50
|
+
json: bool = False, timeout: int = 30) -> Dict[str, Any]:
|
|
51
|
+
"""Make HTTP POST request."""
|
|
52
|
+
if headers is None:
|
|
53
|
+
headers = {}
|
|
54
|
+
|
|
55
|
+
if json and data is not None:
|
|
56
|
+
data = json_lib.dumps(data).encode('utf-8')
|
|
57
|
+
headers['Content-Type'] = 'application/json'
|
|
58
|
+
elif isinstance(data, str):
|
|
59
|
+
data = data.encode('utf-8')
|
|
60
|
+
elif isinstance(data, dict):
|
|
61
|
+
data = urllib.parse.urlencode(data).encode('utf-8')
|
|
62
|
+
|
|
63
|
+
req = urllib.request.Request(url, data=data, headers=headers, method='POST')
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
with urllib.request.urlopen(req, timeout=timeout) as response:
|
|
67
|
+
body = response.read().decode('utf-8')
|
|
68
|
+
return {
|
|
69
|
+
'status': response.status,
|
|
70
|
+
'headers': dict(response.headers),
|
|
71
|
+
'body': body
|
|
72
|
+
}
|
|
73
|
+
except urllib.error.HTTPError as e:
|
|
74
|
+
try:
|
|
75
|
+
error_body = e.read().decode('utf-8')
|
|
76
|
+
except UnicodeDecodeError:
|
|
77
|
+
error_body = e.read().decode('utf-8', errors='replace')
|
|
78
|
+
return {
|
|
79
|
+
'status': e.code,
|
|
80
|
+
'headers': dict(e.headers),
|
|
81
|
+
'body': error_body,
|
|
82
|
+
'error': str(e)
|
|
83
|
+
}
|
|
84
|
+
except Exception as e:
|
|
85
|
+
return {
|
|
86
|
+
'status': 0,
|
|
87
|
+
'headers': {},
|
|
88
|
+
'body': '',
|
|
89
|
+
'error': str(e)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@staticmethod
|
|
93
|
+
def put(url: str, data: Any = None, headers: Optional[Dict[str, str]] = None,
|
|
94
|
+
json: bool = False, timeout: int = 30) -> Dict[str, Any]:
|
|
95
|
+
"""Make HTTP PUT request."""
|
|
96
|
+
if headers is None:
|
|
97
|
+
headers = {}
|
|
98
|
+
|
|
99
|
+
if json and data is not None:
|
|
100
|
+
data = json_lib.dumps(data).encode('utf-8')
|
|
101
|
+
headers['Content-Type'] = 'application/json'
|
|
102
|
+
elif isinstance(data, str):
|
|
103
|
+
data = data.encode('utf-8')
|
|
104
|
+
elif isinstance(data, dict):
|
|
105
|
+
data = urllib.parse.urlencode(data).encode('utf-8')
|
|
106
|
+
|
|
107
|
+
req = urllib.request.Request(url, data=data, headers=headers, method='PUT')
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
with urllib.request.urlopen(req, timeout=timeout) as response:
|
|
111
|
+
body = response.read().decode('utf-8')
|
|
112
|
+
return {
|
|
113
|
+
'status': response.status,
|
|
114
|
+
'headers': dict(response.headers),
|
|
115
|
+
'body': body
|
|
116
|
+
}
|
|
117
|
+
except urllib.error.HTTPError as e:
|
|
118
|
+
try:
|
|
119
|
+
error_body = e.read().decode('utf-8')
|
|
120
|
+
except UnicodeDecodeError:
|
|
121
|
+
error_body = e.read().decode('utf-8', errors='replace')
|
|
122
|
+
return {
|
|
123
|
+
'status': e.code,
|
|
124
|
+
'headers': dict(e.headers),
|
|
125
|
+
'body': error_body,
|
|
126
|
+
'error': str(e)
|
|
127
|
+
}
|
|
128
|
+
except Exception as e:
|
|
129
|
+
return {
|
|
130
|
+
'status': 0,
|
|
131
|
+
'headers': {},
|
|
132
|
+
'body': '',
|
|
133
|
+
'error': str(e)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
@staticmethod
|
|
137
|
+
def delete(url: str, headers: Optional[Dict[str, str]] = None, timeout: int = 30) -> Dict[str, Any]:
|
|
138
|
+
"""Make HTTP DELETE request."""
|
|
139
|
+
if headers is None:
|
|
140
|
+
headers = {}
|
|
141
|
+
|
|
142
|
+
req = urllib.request.Request(url, headers=headers, method='DELETE')
|
|
143
|
+
|
|
144
|
+
try:
|
|
145
|
+
with urllib.request.urlopen(req, timeout=timeout) as response:
|
|
146
|
+
body = response.read().decode('utf-8')
|
|
147
|
+
return {
|
|
148
|
+
'status': response.status,
|
|
149
|
+
'headers': dict(response.headers),
|
|
150
|
+
'body': body
|
|
151
|
+
}
|
|
152
|
+
except urllib.error.HTTPError as e:
|
|
153
|
+
try:
|
|
154
|
+
error_body = e.read().decode('utf-8')
|
|
155
|
+
except UnicodeDecodeError:
|
|
156
|
+
error_body = e.read().decode('utf-8', errors='replace')
|
|
157
|
+
return {
|
|
158
|
+
'status': e.code,
|
|
159
|
+
'headers': dict(e.headers),
|
|
160
|
+
'body': error_body,
|
|
161
|
+
'error': str(e)
|
|
162
|
+
}
|
|
163
|
+
except Exception as e:
|
|
164
|
+
return {
|
|
165
|
+
'status': 0,
|
|
166
|
+
'headers': {},
|
|
167
|
+
'body': '',
|
|
168
|
+
'error': str(e)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
@staticmethod
|
|
172
|
+
def request(method: str, url: str, data: Any = None, headers: Optional[Dict[str, str]] = None,
|
|
173
|
+
timeout: int = 30) -> Dict[str, Any]:
|
|
174
|
+
"""Make HTTP request with custom method."""
|
|
175
|
+
if headers is None:
|
|
176
|
+
headers = {}
|
|
177
|
+
|
|
178
|
+
if data is not None:
|
|
179
|
+
if isinstance(data, str):
|
|
180
|
+
data = data.encode('utf-8')
|
|
181
|
+
elif isinstance(data, dict):
|
|
182
|
+
data = urllib.parse.urlencode(data).encode('utf-8')
|
|
183
|
+
|
|
184
|
+
req = urllib.request.Request(url, data=data, headers=headers, method=method.upper())
|
|
185
|
+
|
|
186
|
+
try:
|
|
187
|
+
with urllib.request.urlopen(req, timeout=timeout) as response:
|
|
188
|
+
body = response.read().decode('utf-8')
|
|
189
|
+
return {
|
|
190
|
+
'status': response.status,
|
|
191
|
+
'headers': dict(response.headers),
|
|
192
|
+
'body': body
|
|
193
|
+
}
|
|
194
|
+
except urllib.error.HTTPError as e:
|
|
195
|
+
try:
|
|
196
|
+
error_body = e.read().decode('utf-8')
|
|
197
|
+
except UnicodeDecodeError:
|
|
198
|
+
error_body = e.read().decode('utf-8', errors='replace')
|
|
199
|
+
return {
|
|
200
|
+
'status': e.code,
|
|
201
|
+
'headers': dict(e.headers),
|
|
202
|
+
'body': error_body,
|
|
203
|
+
'error': str(e)
|
|
204
|
+
}
|
|
205
|
+
except Exception as e:
|
|
206
|
+
return {
|
|
207
|
+
'status': 0,
|
|
208
|
+
'headers': {},
|
|
209
|
+
'body': '',
|
|
210
|
+
'error': str(e)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
# Export functions for easy access
|
|
215
|
+
get = HttpModule.get
|
|
216
|
+
post = HttpModule.post
|
|
217
|
+
put = HttpModule.put
|
|
218
|
+
delete = HttpModule.delete
|
|
219
|
+
request = HttpModule.request
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
"""HTTP Server module for Zexus standard library.
|
|
2
|
+
Built on top of the socket primitives."""
|
|
3
|
+
|
|
4
|
+
import socket
|
|
5
|
+
import threading
|
|
6
|
+
import re
|
|
7
|
+
from typing import Dict, List, Callable, Optional, Any, Tuple
|
|
8
|
+
from urllib.parse import parse_qs, urlparse
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class HTTPRequest:
|
|
12
|
+
"""Represents an HTTP request."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, method: str, path: str, headers: Dict[str, str],
|
|
15
|
+
body: str, query: Dict[str, List[str]]):
|
|
16
|
+
self.method = method
|
|
17
|
+
self.path = path
|
|
18
|
+
self.headers = headers
|
|
19
|
+
self.body = body
|
|
20
|
+
self.query = query
|
|
21
|
+
|
|
22
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
23
|
+
"""Convert to dictionary for Zexus."""
|
|
24
|
+
return {
|
|
25
|
+
'method': self.method,
|
|
26
|
+
'path': self.path,
|
|
27
|
+
'headers': self.headers,
|
|
28
|
+
'body': self.body,
|
|
29
|
+
'query': self.query
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class HTTPResponse:
|
|
34
|
+
"""Represents an HTTP response."""
|
|
35
|
+
|
|
36
|
+
def __init__(self):
|
|
37
|
+
self.status = 200
|
|
38
|
+
self.headers: Dict[str, str] = {'Content-Type': 'text/plain'}
|
|
39
|
+
self.body = ''
|
|
40
|
+
|
|
41
|
+
def set_status(self, code: int) -> 'HTTPResponse':
|
|
42
|
+
"""Set response status code."""
|
|
43
|
+
self.status = code
|
|
44
|
+
return self
|
|
45
|
+
|
|
46
|
+
def set_header(self, name: str, value: str) -> 'HTTPResponse':
|
|
47
|
+
"""Set response header."""
|
|
48
|
+
self.headers[name] = value
|
|
49
|
+
return self
|
|
50
|
+
|
|
51
|
+
def send(self, body: str) -> 'HTTPResponse':
|
|
52
|
+
"""Set response body."""
|
|
53
|
+
self.body = body
|
|
54
|
+
return self
|
|
55
|
+
|
|
56
|
+
def json(self, data: Any) -> 'HTTPResponse':
|
|
57
|
+
"""Send JSON response."""
|
|
58
|
+
import json
|
|
59
|
+
self.headers['Content-Type'] = 'application/json'
|
|
60
|
+
self.body = json.dumps(data)
|
|
61
|
+
return self
|
|
62
|
+
|
|
63
|
+
def build(self) -> str:
|
|
64
|
+
"""Build HTTP response string."""
|
|
65
|
+
status_messages = {
|
|
66
|
+
200: 'OK',
|
|
67
|
+
201: 'Created',
|
|
68
|
+
400: 'Bad Request',
|
|
69
|
+
404: 'Not Found',
|
|
70
|
+
500: 'Internal Server Error'
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
status_msg = status_messages.get(self.status, 'OK')
|
|
74
|
+
response = f"HTTP/1.1 {self.status} {status_msg}\r\n"
|
|
75
|
+
|
|
76
|
+
# Add Content-Length
|
|
77
|
+
self.headers['Content-Length'] = str(len(self.body.encode('utf-8')))
|
|
78
|
+
|
|
79
|
+
# Add headers
|
|
80
|
+
for name, value in self.headers.items():
|
|
81
|
+
response += f"{name}: {value}\r\n"
|
|
82
|
+
|
|
83
|
+
response += "\r\n"
|
|
84
|
+
response += self.body
|
|
85
|
+
|
|
86
|
+
return response
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class HTTPServer:
|
|
90
|
+
"""Simple HTTP server with routing."""
|
|
91
|
+
|
|
92
|
+
def __init__(self, host: str = '0.0.0.0', port: int = 8080):
|
|
93
|
+
self.host = host
|
|
94
|
+
self.port = port
|
|
95
|
+
self.routes: Dict[Tuple[str, str], Callable] = {} # (method, path) -> handler
|
|
96
|
+
self.socket: Optional[socket.socket] = None
|
|
97
|
+
self.running = False
|
|
98
|
+
self.thread: Optional[threading.Thread] = None
|
|
99
|
+
|
|
100
|
+
def route(self, method: str, path: str, handler: Callable):
|
|
101
|
+
"""Register a route handler."""
|
|
102
|
+
self.routes[(method.upper(), path)] = handler
|
|
103
|
+
|
|
104
|
+
def get(self, path: str, handler: Callable):
|
|
105
|
+
"""Register GET route."""
|
|
106
|
+
self.route('GET', path, handler)
|
|
107
|
+
|
|
108
|
+
def post(self, path: str, handler: Callable):
|
|
109
|
+
"""Register POST route."""
|
|
110
|
+
self.route('POST', path, handler)
|
|
111
|
+
|
|
112
|
+
def put(self, path: str, handler: Callable):
|
|
113
|
+
"""Register PUT route."""
|
|
114
|
+
self.route('PUT', path, handler)
|
|
115
|
+
|
|
116
|
+
def delete(self, path: str, handler: Callable):
|
|
117
|
+
"""Register DELETE route."""
|
|
118
|
+
self.route('DELETE', path, handler)
|
|
119
|
+
|
|
120
|
+
def _parse_request(self, raw_request: str) -> Optional[HTTPRequest]:
|
|
121
|
+
"""Parse raw HTTP request."""
|
|
122
|
+
try:
|
|
123
|
+
lines = raw_request.split('\r\n')
|
|
124
|
+
if not lines:
|
|
125
|
+
return None
|
|
126
|
+
|
|
127
|
+
# Parse request line
|
|
128
|
+
request_line = lines[0]
|
|
129
|
+
parts = request_line.split(' ')
|
|
130
|
+
if len(parts) < 3:
|
|
131
|
+
return None
|
|
132
|
+
|
|
133
|
+
method, full_path, _ = parts
|
|
134
|
+
|
|
135
|
+
# Parse path and query string
|
|
136
|
+
parsed = urlparse(full_path)
|
|
137
|
+
path = parsed.path
|
|
138
|
+
query = parse_qs(parsed.query)
|
|
139
|
+
|
|
140
|
+
# Parse headers
|
|
141
|
+
headers = {}
|
|
142
|
+
body_start = 0
|
|
143
|
+
for i, line in enumerate(lines[1:], 1):
|
|
144
|
+
if line == '':
|
|
145
|
+
body_start = i + 1
|
|
146
|
+
break
|
|
147
|
+
if ': ' in line:
|
|
148
|
+
name, value = line.split(': ', 1)
|
|
149
|
+
headers[name] = value
|
|
150
|
+
|
|
151
|
+
# Parse body
|
|
152
|
+
body = '\r\n'.join(lines[body_start:]) if body_start > 0 else ''
|
|
153
|
+
|
|
154
|
+
return HTTPRequest(method, path, headers, body, query)
|
|
155
|
+
|
|
156
|
+
except Exception as e:
|
|
157
|
+
print(f"Request parse error: {e}")
|
|
158
|
+
return None
|
|
159
|
+
|
|
160
|
+
def _handle_connection(self, client_socket: socket.socket, address: tuple):
|
|
161
|
+
"""Handle a client connection."""
|
|
162
|
+
try:
|
|
163
|
+
# Receive request
|
|
164
|
+
raw_request = client_socket.recv(8192).decode('utf-8')
|
|
165
|
+
|
|
166
|
+
if not raw_request:
|
|
167
|
+
return
|
|
168
|
+
|
|
169
|
+
# Parse request
|
|
170
|
+
request = self._parse_request(raw_request)
|
|
171
|
+
if not request:
|
|
172
|
+
response = HTTPResponse().set_status(400).send("Bad Request")
|
|
173
|
+
client_socket.sendall(response.build().encode('utf-8'))
|
|
174
|
+
return
|
|
175
|
+
|
|
176
|
+
# Find matching route
|
|
177
|
+
route_key = (request.method, request.path)
|
|
178
|
+
handler = self.routes.get(route_key)
|
|
179
|
+
|
|
180
|
+
if not handler:
|
|
181
|
+
response = HTTPResponse().set_status(404).send("Not Found")
|
|
182
|
+
client_socket.sendall(response.build().encode('utf-8'))
|
|
183
|
+
return
|
|
184
|
+
|
|
185
|
+
# Create response object
|
|
186
|
+
response = HTTPResponse()
|
|
187
|
+
|
|
188
|
+
# Call handler
|
|
189
|
+
try:
|
|
190
|
+
handler(request, response)
|
|
191
|
+
except Exception as e:
|
|
192
|
+
print(f"Handler error: {e}")
|
|
193
|
+
response = HTTPResponse().set_status(500).send(f"Internal Server Error: {str(e)}")
|
|
194
|
+
|
|
195
|
+
# Send response
|
|
196
|
+
client_socket.sendall(response.build().encode('utf-8'))
|
|
197
|
+
|
|
198
|
+
except Exception as e:
|
|
199
|
+
print(f"Connection handler error: {e}")
|
|
200
|
+
|
|
201
|
+
finally:
|
|
202
|
+
try:
|
|
203
|
+
client_socket.close()
|
|
204
|
+
except:
|
|
205
|
+
pass
|
|
206
|
+
|
|
207
|
+
def listen(self):
|
|
208
|
+
"""Start the HTTP server."""
|
|
209
|
+
if self.running:
|
|
210
|
+
raise RuntimeError("Server is already running")
|
|
211
|
+
|
|
212
|
+
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
213
|
+
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
214
|
+
self.socket.bind((self.host, self.port))
|
|
215
|
+
self.socket.listen(10)
|
|
216
|
+
self.running = True
|
|
217
|
+
|
|
218
|
+
print(f"HTTP Server listening on {self.host}:{self.port}")
|
|
219
|
+
|
|
220
|
+
# Accept connections
|
|
221
|
+
while self.running:
|
|
222
|
+
try:
|
|
223
|
+
self.socket.settimeout(1.0)
|
|
224
|
+
client_socket, address = self.socket.accept()
|
|
225
|
+
|
|
226
|
+
# Handle in new thread
|
|
227
|
+
handler_thread = threading.Thread(
|
|
228
|
+
target=self._handle_connection,
|
|
229
|
+
args=(client_socket, address),
|
|
230
|
+
daemon=True
|
|
231
|
+
)
|
|
232
|
+
handler_thread.start()
|
|
233
|
+
|
|
234
|
+
except socket.timeout:
|
|
235
|
+
continue
|
|
236
|
+
except Exception as e:
|
|
237
|
+
if self.running:
|
|
238
|
+
print(f"Accept error: {e}")
|
|
239
|
+
break
|
|
240
|
+
|
|
241
|
+
def stop(self):
|
|
242
|
+
"""Stop the server."""
|
|
243
|
+
self.running = False
|
|
244
|
+
if self.socket:
|
|
245
|
+
try:
|
|
246
|
+
self.socket.close()
|
|
247
|
+
except:
|
|
248
|
+
pass
|