flyshell 1.1.2__tar.gz → 1.1.4__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.
Files changed (34) hide show
  1. {flyshell-1.1.2/src/flyshell.egg-info → flyshell-1.1.4}/PKG-INFO +1 -1
  2. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/abstract/parent_cmd.py +12 -12
  3. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/builtin/utils.py +2 -2
  4. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/constants.py +2 -2
  5. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/core/loader.py +8 -9
  6. {flyshell-1.1.2 → flyshell-1.1.4/src/flyshell.egg-info}/PKG-INFO +1 -1
  7. {flyshell-1.1.2 → flyshell-1.1.4}/tests/test_loader.py +12 -0
  8. {flyshell-1.1.2 → flyshell-1.1.4}/LICENSE +0 -0
  9. {flyshell-1.1.2 → flyshell-1.1.4}/README.md +0 -0
  10. {flyshell-1.1.2 → flyshell-1.1.4}/pyproject.toml +0 -0
  11. {flyshell-1.1.2 → flyshell-1.1.4}/setup.cfg +0 -0
  12. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/__init__.py +0 -0
  13. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/abstract/__init__.py +0 -0
  14. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/abstract/base_cmd.py +0 -0
  15. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/abstract/base_plugin.py +0 -0
  16. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/builtin/__init__.py +0 -0
  17. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/builtin/diskops.py +0 -0
  18. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/builtin/fs.py +0 -0
  19. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/builtin/system.py +0 -0
  20. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/core/__init__.py +0 -0
  21. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/core/auth.py +0 -0
  22. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/core/console.py +0 -0
  23. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/core/data.py +0 -0
  24. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/core/directory.py +0 -0
  25. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell/main.py +0 -0
  26. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell.egg-info/SOURCES.txt +0 -0
  27. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell.egg-info/dependency_links.txt +0 -0
  28. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell.egg-info/entry_points.txt +0 -0
  29. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell.egg-info/requires.txt +0 -0
  30. {flyshell-1.1.2 → flyshell-1.1.4}/src/flyshell.egg-info/top_level.txt +0 -0
  31. {flyshell-1.1.2 → flyshell-1.1.4}/tests/test_auth.py +0 -0
  32. {flyshell-1.1.2 → flyshell-1.1.4}/tests/test_data.py +0 -0
  33. {flyshell-1.1.2 → flyshell-1.1.4}/tests/test_directory.py +0 -0
  34. {flyshell-1.1.2 → flyshell-1.1.4}/tests/test_security.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flyshell
3
- Version: 1.1.2
3
+ Version: 1.1.4
4
4
  Summary: A modular, zero-dependency command-line environment in Python.
5
5
  License: MIT
6
6
  Requires-Python: >=3.10
@@ -43,28 +43,28 @@ class ParentCmd(BaseCmd):
43
43
  f"\nFor subcommand assistance use '{self.name} <subcmd> -h' or '--help'\n"
44
44
  )
45
45
 
46
- def execute(self, args: List[str]) -> Union[int, Tuple[int, str], str, None]:
46
+ def execute(self, args: List[str]) -> Tuple[int, str]:
47
47
  if not args or args[0] in ("-h", "--help"):
48
48
  self.help()
49
- return 0
49
+ return (0, "")
50
50
  sub_name = args[0].lower()
51
51
  sub_args = args[1:]
52
52
  if sub_name not in self._sub_registry:
53
- print(
54
- f"\nCommand Error: Unknown subcommand '{sub_name}' for '{self.name}'."
53
+ err = (
54
+ f"\nCommand Error: Unknown subcommand '{sub_name}' for '{self.name}'.\n"
55
+ f"Use '{self.name} -h' or '--help' to see all valid subcommands.\n"
55
56
  )
56
- print(f"Use '{self.name} -h' or '--help' to see all valid subcommands.\n")
57
- return 1
57
+ return (1, err)
58
58
  target = self._sub_registry[sub_name]
59
59
  if "-h" in sub_args or "--help" in sub_args:
60
60
  target.help(prefix=self.name)
61
- return 0
61
+ return (0, "")
62
62
  if len(sub_args) < target.min_args:
63
- print(
63
+ err_lines = [
64
64
  f"\nCommand Error: '{self.name} {target.name}' requires at least {target.min_args} argument(s)."
65
- )
65
+ ]
66
66
  if target.options:
67
- print(f"Accepted arguments: {target.options}")
68
- print()
69
- return 1
67
+ err_lines.append(f"Accepted arguments: {target.options}")
68
+ err_lines.append("")
69
+ return (1, "\n".join(err_lines))
70
70
  return target.execute(sub_args)
@@ -83,8 +83,7 @@ class Kill(BaseCmd):
83
83
  if choice == "y":
84
84
  print("\nShutting down...")
85
85
  sys.exit(0)
86
- else:
87
- return (1, "\nAction cancelled.\n")
86
+ return (1, "\nAction cancelled.\n")
88
87
 
89
88
 
90
89
  class Reboot(BaseCmd):
@@ -113,6 +112,7 @@ class Reboot(BaseCmd):
113
112
  signal.signal(signal.SIGINT, old_handler)
114
113
  else:
115
114
  os.execv(cmd[0], cmd)
115
+ return (0, "")
116
116
 
117
117
 
118
118
  class Sleep(BaseCmd):
@@ -5,8 +5,8 @@ import os
5
5
  import platform
6
6
  import time
7
7
 
8
- BUILD = 115
9
- VERSION = "1.1.2"
8
+ BUILD = 117
9
+ VERSION = "1.1.4"
10
10
 
11
11
 
12
12
  def _resolve_app_dir() -> Path:
@@ -33,10 +33,17 @@ def scan_plugins(plugin_folder=None):
33
33
  if entry.exists():
34
34
  file_path = entry
35
35
  plugin_name = item.name
36
- if not file_path:
36
+ if not file_path or not plugin_name:
37
+ continue
38
+ if plugin_name in RESERVED_NAMES:
39
+ print(
40
+ f"\n⚠️ Collision Error - Plugin '{plugin_name}' conflicts with a built-in Flyshell command and will not be loaded."
41
+ )
37
42
  continue
38
43
  try:
39
44
  spec = importlib.util.spec_from_file_location(plugin_name, file_path)
45
+ if spec is None or spec.loader is None:
46
+ continue
40
47
  module = importlib.util.module_from_spec(spec)
41
48
  spec.loader.exec_module(module)
42
49
  for _, obj in inspect.getmembers(module, inspect.isclass):
@@ -51,12 +58,6 @@ def scan_plugins(plugin_folder=None):
51
58
  loaded_count = 0
52
59
  first_print = True
53
60
  for name, entries in candidates.items():
54
- failed = False
55
- if name in RESERVED_NAMES:
56
- print(
57
- f"\n⚠️ Collision Error - Plugin '{name}' conflicts with a built-in Flyshell command and will not be loaded."
58
- )
59
- failed = True
60
61
  if len(entries) > 1:
61
62
  paths = "\n - ".join(str(path) for _, path in entries)
62
63
  print(
@@ -65,8 +66,6 @@ def scan_plugins(plugin_folder=None):
65
66
  print(
66
67
  "The above plugins will not be loaded. Please rename them to unique names."
67
68
  )
68
- failed = True
69
- if failed:
70
69
  continue
71
70
  instance, _ = entries[0]
72
71
  c.PLUGINS[name] = instance
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flyshell
3
- Version: 1.1.2
3
+ Version: 1.1.4
4
4
  Summary: A modular, zero-dependency command-line environment in Python.
5
5
  License: MIT
6
6
  Requires-Python: >=3.10
@@ -41,3 +41,15 @@ def test_loader_handles_broken_plugin_gracefully(tmp_path, monkeypatch):
41
41
  monkeypatch.setattr(c, "USER_PLUGIN_DIR", tmp_path)
42
42
  loader.scan_plugins(plugin_folder=tmp_path)
43
43
  assert "broken" not in c.PLUGINS
44
+
45
+
46
+ def test_loader_does_not_execute_code_in_reserved_plugin(tmp_path, monkeypatch):
47
+ sentinel = tmp_path / "sentinel.txt"
48
+ bad_plugin = tmp_path / "cd.py"
49
+ bad_plugin.write_text(
50
+ f"from pathlib import Path\nPath('{sentinel.as_posix()}').write_text('executed')\n"
51
+ )
52
+ monkeypatch.setattr(c, "USER_PLUGIN_DIR", tmp_path)
53
+ loader.scan_plugins(plugin_folder=tmp_path)
54
+ assert "cd" not in c.PLUGINS
55
+ assert not sentinel.exists()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes