qyro 2.0.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 (45) hide show
  1. qyro/__init__.py +17 -0
  2. qyro/adapters/__init__.py +4 -0
  3. qyro/adapters/language_adapters/__init__.py +4 -0
  4. qyro/adapters/language_adapters/c/__init__.py +4 -0
  5. qyro/adapters/language_adapters/python/__init__.py +4 -0
  6. qyro/adapters/language_adapters/python/python_adapter.py +584 -0
  7. qyro/cli/__init__.py +8 -0
  8. qyro/cli/__main__.py +5 -0
  9. qyro/cli/cli.py +392 -0
  10. qyro/cli/interactive.py +297 -0
  11. qyro/common/__init__.py +37 -0
  12. qyro/common/animation.py +82 -0
  13. qyro/common/builder.py +434 -0
  14. qyro/common/compiler.py +895 -0
  15. qyro/common/config.py +93 -0
  16. qyro/common/constants.py +99 -0
  17. qyro/common/errors.py +176 -0
  18. qyro/common/frontend.py +74 -0
  19. qyro/common/health.py +358 -0
  20. qyro/common/kafka_manager.py +192 -0
  21. qyro/common/logging.py +149 -0
  22. qyro/common/memory.py +147 -0
  23. qyro/common/metrics.py +301 -0
  24. qyro/common/monitoring.py +468 -0
  25. qyro/common/parser.py +91 -0
  26. qyro/common/platform.py +609 -0
  27. qyro/common/redis_memory.py +1108 -0
  28. qyro/common/rpc.py +287 -0
  29. qyro/common/sandbox.py +191 -0
  30. qyro/common/schema_loader.py +33 -0
  31. qyro/common/secure_sandbox.py +490 -0
  32. qyro/common/toolchain_validator.py +617 -0
  33. qyro/common/type_generator.py +176 -0
  34. qyro/common/validation.py +401 -0
  35. qyro/common/validator.py +204 -0
  36. qyro/gateway/__init__.py +8 -0
  37. qyro/gateway/gateway.py +303 -0
  38. qyro/orchestrator/__init__.py +8 -0
  39. qyro/orchestrator/orchestrator.py +1223 -0
  40. qyro-2.0.0.dist-info/METADATA +244 -0
  41. qyro-2.0.0.dist-info/RECORD +45 -0
  42. qyro-2.0.0.dist-info/WHEEL +5 -0
  43. qyro-2.0.0.dist-info/entry_points.txt +2 -0
  44. qyro-2.0.0.dist-info/licenses/LICENSE +21 -0
  45. qyro-2.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,609 @@
1
+ """
2
+ Nexus Platform Abstraction Layer
3
+ Provides cross-platform utilities for path handling, executable extensions,
4
+ and command execution. Abstracts away Windows vs Unix differences.
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ import subprocess
10
+ import shutil
11
+ import platform
12
+ from typing import List, Optional, Tuple, Union
13
+ from pathlib import Path
14
+ from enum import Enum
15
+
16
+ from .logging import get_logger
17
+
18
+ logger = get_logger("nexus.platform")
19
+
20
+
21
+ class PlatformType(Enum):
22
+ """Supported platform types."""
23
+ WINDOWS = "windows"
24
+ LINUX = "linux"
25
+ MACOS = "macos"
26
+ UNKNOWN = "unknown"
27
+
28
+
29
+ class Platform:
30
+ """
31
+ Platform abstraction layer for cross-platform compatibility.
32
+
33
+ Provides utilities for:
34
+ - Path handling (Windows vs Unix paths)
35
+ - Executable extensions (.exe on Windows, none on Unix)
36
+ - Command execution and subprocess handling
37
+ - Platform-specific operations
38
+ """
39
+
40
+ _instance = None
41
+
42
+ def __new__(cls):
43
+ """Singleton pattern to ensure consistent platform detection."""
44
+ if cls._instance is None:
45
+ cls._instance = super().__new__(cls)
46
+ cls._instance._initialized = False
47
+ return cls._instance
48
+
49
+ def __init__(self):
50
+ """Initialize platform detection."""
51
+ if self._initialized:
52
+ return
53
+
54
+ self._initialized = True
55
+ self._detect_platform()
56
+ self._setup_platform_specifics()
57
+
58
+ def _detect_platform(self):
59
+ """Detect the current platform."""
60
+ if sys.platform == 'win32':
61
+ self.type = PlatformType.WINDOWS
62
+ self.name = 'windows'
63
+ elif sys.platform == 'darwin':
64
+ self.type = PlatformType.MACOS
65
+ self.name = 'macos'
66
+ elif sys.platform.startswith('linux'):
67
+ self.type = PlatformType.LINUX
68
+ self.name = 'linux'
69
+ else:
70
+ self.type = PlatformType.UNKNOWN
71
+ self.name = 'unknown'
72
+
73
+ logger.info("platform_detected", platform=self.name, sys_platform=sys.platform)
74
+
75
+ def _setup_platform_specifics(self):
76
+ """Setup platform-specific settings."""
77
+ # Path separator
78
+ self.path_sep = os.sep
79
+ self.path_list_sep = os.pathsep
80
+
81
+ # Executable extension
82
+ self.exe_extension = '.exe' if self.type == PlatformType.WINDOWS else ''
83
+
84
+ # Shell settings
85
+ self.use_shell = self.type == PlatformType.WINDOWS
86
+
87
+ # Default shell
88
+ if self.type == PlatformType.WINDOWS:
89
+ self.default_shell = os.environ.get('COMSPEC', 'cmd.exe')
90
+ else:
91
+ self.default_shell = os.environ.get('SHELL', '/bin/sh')
92
+
93
+ # Newline
94
+ self.newline = os.linesep
95
+
96
+ # Null device
97
+ self.null_device = 'NUL' if self.type == PlatformType.WINDOWS else '/dev/null'
98
+
99
+ # Temporary directory
100
+ self.temp_dir = os.environ.get('TEMP', '/tmp') if self.type == PlatformType.WINDOWS else '/tmp'
101
+
102
+ # Home directory
103
+ self.home_dir = os.path.expanduser('~')
104
+
105
+ # Path handling methods
106
+
107
+ def normalize_path(self, path: str) -> str:
108
+ """
109
+ Normalize a path for the current platform.
110
+
111
+ Args:
112
+ path: Path to normalize
113
+
114
+ Returns:
115
+ Normalized path
116
+ """
117
+ # Convert to absolute path
118
+ path = os.path.abspath(path)
119
+
120
+ # Normalize path separators
121
+ path = os.path.normpath(path)
122
+
123
+ return path
124
+
125
+ def join_path(self, *parts: str) -> str:
126
+ """
127
+ Join path parts using the platform-specific separator.
128
+
129
+ Args:
130
+ *parts: Path parts to join
131
+
132
+ Returns:
133
+ Joined path
134
+ """
135
+ return os.path.join(*parts)
136
+
137
+ def split_path(self, path: str) -> List[str]:
138
+ """
139
+ Split a path into components.
140
+
141
+ Args:
142
+ path: Path to split
143
+
144
+ Returns:
145
+ List of path components
146
+ """
147
+ return list(Path(path).parts)
148
+
149
+ def get_basename(self, path: str) -> str:
150
+ """
151
+ Get the basename (filename) from a path.
152
+
153
+ Args:
154
+ path: Path to extract basename from
155
+
156
+ Returns:
157
+ Basename
158
+ """
159
+ return os.path.basename(path)
160
+
161
+ def get_dirname(self, path: str) -> str:
162
+ """
163
+ Get the directory name from a path.
164
+
165
+ Args:
166
+ path: Path to extract directory from
167
+
168
+ Returns:
169
+ Directory name
170
+ """
171
+ return os.path.dirname(path)
172
+
173
+ def get_extension(self, path: str) -> str:
174
+ """
175
+ Get the file extension from a path.
176
+
177
+ Args:
178
+ path: Path to extract extension from
179
+
180
+ Returns:
181
+ File extension (including the dot)
182
+ """
183
+ return os.path.splitext(path)[1]
184
+
185
+ def remove_extension(self, path: str) -> str:
186
+ """
187
+ Remove the file extension from a path.
188
+
189
+ Args:
190
+ path: Path to remove extension from
191
+
192
+ Returns:
193
+ Path without extension
194
+ """
195
+ return os.path.splitext(path)[0]
196
+
197
+ # Executable handling methods
198
+
199
+ def get_executable_name(self, name: str) -> str:
200
+ """
201
+ Add platform-specific executable extension to a name.
202
+
203
+ Args:
204
+ name: Base name of the executable
205
+
206
+ Returns:
207
+ Name with appropriate extension
208
+ """
209
+ if not name.endswith(self.exe_extension):
210
+ return name + self.exe_extension
211
+ return name
212
+
213
+ def is_executable(self, path: str) -> bool:
214
+ """
215
+ Check if a file is executable.
216
+
217
+ Args:
218
+ path: Path to check
219
+
220
+ Returns:
221
+ True if executable, False otherwise
222
+ """
223
+ if not os.path.isfile(path):
224
+ return False
225
+
226
+ if self.type == PlatformType.WINDOWS:
227
+ # On Windows, check for executable extensions
228
+ ext = self.get_extension(path).lower()
229
+ return ext in ['.exe', '.bat', '.cmd', '.ps1']
230
+ else:
231
+ # On Unix, check execute permission
232
+ return os.access(path, os.X_OK)
233
+
234
+ def which(self, command: str) -> Optional[str]:
235
+ """
236
+ Find the full path to an executable command.
237
+
238
+ Args:
239
+ command: Command to find
240
+
241
+ Returns:
242
+ Full path if found, None otherwise
243
+ """
244
+ return shutil.which(command)
245
+
246
+ # Command execution methods
247
+
248
+ def run_command(
249
+ self,
250
+ cmd: Union[str, List[str]],
251
+ cwd: Optional[str] = None,
252
+ env: Optional[dict] = None,
253
+ timeout: Optional[int] = None,
254
+ capture_output: bool = True,
255
+ shell: Optional[bool] = None,
256
+ text: bool = True,
257
+ ) -> Tuple[int, str, str]:
258
+ """
259
+ Run a command with cross-platform compatibility.
260
+
261
+ Args:
262
+ cmd: Command to run (string or list)
263
+ cwd: Working directory
264
+ env: Environment variables
265
+ timeout: Timeout in seconds
266
+ capture_output: Whether to capture stdout/stderr
267
+ shell: Whether to use shell (default: platform-specific)
268
+ text: Whether to return text instead of bytes
269
+
270
+ Returns:
271
+ Tuple of (returncode, stdout, stderr)
272
+ """
273
+ if shell is None:
274
+ shell = self.use_shell
275
+
276
+ # Convert string command to list if needed
277
+ if isinstance(cmd, str) and not shell:
278
+ # On Unix, we need to split the command
279
+ if self.type != PlatformType.WINDOWS:
280
+ import shlex
281
+ cmd = shlex.split(cmd)
282
+
283
+ try:
284
+ result = subprocess.run(
285
+ cmd,
286
+ cwd=cwd,
287
+ env=env,
288
+ timeout=timeout,
289
+ capture_output=capture_output,
290
+ shell=shell,
291
+ text=text,
292
+ encoding='utf-8',
293
+ errors='replace'
294
+ )
295
+ return result.returncode, result.stdout, result.stderr
296
+ except FileNotFoundError:
297
+ return 1, "", f"Command not found: {cmd}"
298
+ except subprocess.TimeoutExpired:
299
+ return 1, "", f"Command timed out after {timeout} seconds"
300
+ except Exception as e:
301
+ return 1, "", str(e)
302
+
303
+ def kill_process(self, pid: int, force: bool = False) -> bool:
304
+ """
305
+ Kill a process by PID.
306
+
307
+ Args:
308
+ pid: Process ID
309
+ force: Whether to force kill
310
+
311
+ Returns:
312
+ True if successful, False otherwise
313
+ """
314
+ try:
315
+ if self.type == PlatformType.WINDOWS:
316
+ import signal
317
+ sig = signal.SIGTERM if not force else signal.SIGKILL
318
+ os.kill(pid, sig)
319
+ else:
320
+ import signal
321
+ sig = signal.SIGTERM if not force else signal.SIGKILL
322
+ os.kill(pid, sig)
323
+ return True
324
+ except Exception as e:
325
+ logger.warning("kill_process_failed", pid=pid, error=str(e))
326
+ return False
327
+
328
+ def kill_process_by_name(self, name: str, force: bool = False) -> bool:
329
+ """
330
+ Kill processes by name.
331
+
332
+ Args:
333
+ name: Process name (exact match, no wildcards)
334
+ force: Whether to force kill
335
+
336
+ Returns:
337
+ True if successful, False otherwise
338
+ """
339
+ try:
340
+ if self.type == PlatformType.WINDOWS:
341
+ # Use wmic to get exact process names and then kill by PID
342
+ # This prevents killing processes that start with the same name
343
+ cmd = ['wmic', 'process', 'where', f'name="{name}"', 'get', 'processid', '/value']
344
+ result = subprocess.run(cmd, capture_output=True, text=True)
345
+
346
+ if result.returncode == 0 and result.stdout.strip():
347
+ # Extract PIDs from wmic output
348
+ lines = result.stdout.strip().split('\n')
349
+ for line in lines:
350
+ if line.strip().startswith('ProcessId='):
351
+ try:
352
+ pid = int(line.split('=')[1].strip())
353
+ if pid > 0:
354
+ self.kill_process(pid, force)
355
+ except (ValueError, IndexError):
356
+ continue
357
+ return True
358
+ else:
359
+ # Fallback to tasklist to find exact matches
360
+ cmd = ['tasklist', '/FI', f'IMAGENAME eq {name}', '/FO', 'CSV']
361
+ result = subprocess.run(cmd, capture_output=True, text=True)
362
+
363
+ if result.returncode == 0 and result.stdout.strip():
364
+ lines = result.stdout.strip().split('\n')
365
+ for line in lines[1:]: # Skip header
366
+ if line:
367
+ try:
368
+ # CSV format: "process_name.exe",PID,...
369
+ process_name = line.split(',')[0].strip().strip('"')
370
+ if process_name.lower() == name.lower():
371
+ pid = int(line.split(',')[1].strip().strip('"'))
372
+ self.kill_process(pid, force)
373
+ except (ValueError, IndexError):
374
+ continue
375
+ return True
376
+ else:
377
+ # Use pgrep to get exact process IDs on Unix systems
378
+ cmd = ['pgrep', '-f', f'^{name}$|^./{name}$']
379
+ result = subprocess.run(cmd, capture_output=True, text=True)
380
+
381
+ if result.returncode == 0 and result.stdout.strip():
382
+ pids = result.stdout.strip().split('\n')
383
+ for pid_str in pids:
384
+ try:
385
+ pid = int(pid_str.strip())
386
+ self.kill_process(pid, force)
387
+ except ValueError:
388
+ continue
389
+ else:
390
+ # Fallback: use pkill with exact match
391
+ cmd = ['pkill', '-x', name] # -x for exact match
392
+ if force:
393
+ cmd.insert(1, '-9')
394
+ result = subprocess.run(cmd, capture_output=True)
395
+ return result.returncode == 0
396
+ return True
397
+ except Exception as e:
398
+ logger.warning("kill_process_by_name_failed", name=name, error=str(e))
399
+ return False
400
+
401
+ # File system methods
402
+
403
+ def ensure_dir(self, path: str) -> str:
404
+ """
405
+ Ensure a directory exists, creating it if necessary.
406
+
407
+ Args:
408
+ path: Directory path
409
+
410
+ Returns:
411
+ Path to the directory
412
+ """
413
+ os.makedirs(path, exist_ok=True)
414
+ return path
415
+
416
+ def remove_file(self, path: str) -> bool:
417
+ """
418
+ Remove a file if it exists.
419
+
420
+ Args:
421
+ path: Path to file
422
+
423
+ Returns:
424
+ True if removed or didn't exist, False on error
425
+ """
426
+ try:
427
+ if os.path.exists(path):
428
+ os.remove(path)
429
+ return True
430
+ except Exception as e:
431
+ logger.warning("remove_file_failed", path=path, error=str(e))
432
+ return False
433
+
434
+ def remove_dir(self, path: str) -> bool:
435
+ """
436
+ Remove a directory if it exists.
437
+
438
+ Args:
439
+ path: Path to directory
440
+
441
+ Returns:
442
+ True if removed or didn't exist, False on error
443
+ """
444
+ try:
445
+ if os.path.exists(path):
446
+ shutil.rmtree(path)
447
+ return True
448
+ except Exception as e:
449
+ logger.warning("remove_dir_failed", path=path, error=str(e))
450
+ return False
451
+
452
+ # Environment methods
453
+
454
+ def get_env_var(self, name: str, default: Optional[str] = None) -> Optional[str]:
455
+ """
456
+ Get an environment variable.
457
+
458
+ Args:
459
+ name: Variable name
460
+ default: Default value if not found
461
+
462
+ Returns:
463
+ Variable value or default
464
+ """
465
+ return os.environ.get(name, default)
466
+
467
+ def set_env_var(self, name: str, value: str):
468
+ """
469
+ Set an environment variable.
470
+
471
+ Args:
472
+ name: Variable name
473
+ value: Variable value
474
+ """
475
+ os.environ[name] = value
476
+
477
+ def get_path_env(self) -> List[str]:
478
+ """
479
+ Get the PATH environment variable as a list.
480
+
481
+ Returns:
482
+ List of paths
483
+ """
484
+ path_str = self.get_env_var('PATH', '')
485
+ return path_str.split(self.path_list_sep) if path_str else []
486
+
487
+ def add_to_path(self, path: str, prepend: bool = True):
488
+ """
489
+ Add a path to the PATH environment variable.
490
+
491
+ Args:
492
+ path: Path to add
493
+ prepend: Whether to add to the beginning
494
+ """
495
+ current_path = self.get_path_env()
496
+
497
+ if path in current_path:
498
+ return # Already in PATH
499
+
500
+ if prepend:
501
+ current_path.insert(0, path)
502
+ else:
503
+ current_path.append(path)
504
+
505
+ self.set_env_var('PATH', self.path_list_sep.join(current_path))
506
+
507
+ # Utility methods
508
+
509
+ def is_windows(self) -> bool:
510
+ """Check if running on Windows."""
511
+ return self.type == PlatformType.WINDOWS
512
+
513
+ def is_linux(self) -> bool:
514
+ """Check if running on Linux."""
515
+ return self.type == PlatformType.LINUX
516
+
517
+ def is_macos(self) -> bool:
518
+ """Check if running on macOS."""
519
+ return self.type == PlatformType.MACOS
520
+
521
+ def get_platform_info(self) -> dict:
522
+ """
523
+ Get platform information.
524
+
525
+ Returns:
526
+ Dictionary with platform details
527
+ """
528
+ return {
529
+ 'type': self.type.value,
530
+ 'name': self.name,
531
+ 'system': platform.system(),
532
+ 'release': platform.release(),
533
+ 'version': platform.version(),
534
+ 'machine': platform.machine(),
535
+ 'processor': platform.processor(),
536
+ 'python_version': platform.python_version(),
537
+ 'executable_extension': self.exe_extension,
538
+ 'path_separator': self.path_sep,
539
+ }
540
+
541
+ def print_platform_info(self):
542
+ """Print platform information."""
543
+ info = self.get_platform_info()
544
+ print("\n" + "=" * 60)
545
+ print("PLATFORM INFORMATION")
546
+ print("=" * 60)
547
+ for key, value in info.items():
548
+ print(f"{key:20}: {value}")
549
+ print("=" * 60 + "\n")
550
+
551
+
552
+ # Global platform instance
553
+ _platform = None
554
+
555
+
556
+ def get_platform() -> Platform:
557
+ """
558
+ Get the global platform instance.
559
+
560
+ Returns:
561
+ Platform instance
562
+ """
563
+ global _platform
564
+ if _platform is None:
565
+ _platform = Platform()
566
+ return _platform
567
+
568
+
569
+ # Convenience functions for common operations
570
+
571
+ def normalize_path(path: str) -> str:
572
+ """Normalize a path for the current platform."""
573
+ return get_platform().normalize_path(path)
574
+
575
+
576
+ def join_path(*parts: str) -> str:
577
+ """Join path parts using the platform-specific separator."""
578
+ return get_platform().join_path(*parts)
579
+
580
+
581
+ def get_executable_name(name: str) -> str:
582
+ """Add platform-specific executable extension to a name."""
583
+ return get_platform().get_executable_name(name)
584
+
585
+
586
+ def run_command(cmd: Union[str, List[str]], **kwargs) -> Tuple[int, str, str]:
587
+ """Run a command with cross-platform compatibility."""
588
+ return get_platform().run_command(cmd, **kwargs)
589
+
590
+
591
+ def is_windows() -> bool:
592
+ """Check if running on Windows."""
593
+ return get_platform().is_windows()
594
+
595
+
596
+ def is_linux() -> bool:
597
+ """Check if running on Linux."""
598
+ return get_platform().is_linux()
599
+
600
+
601
+ def is_macos() -> bool:
602
+ """Check if running on macOS."""
603
+ return get_platform().is_macos()
604
+
605
+
606
+ if __name__ == "__main__":
607
+ # Print platform information when executed directly
608
+ platform = get_platform()
609
+ platform.print_platform_info()