python-template-project 0.1.0__py3-none-any.whl → 0.1.18__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.
__init__.py ADDED
File without changes
firewall_handler.py ADDED
@@ -0,0 +1,198 @@
1
+ import os
2
+ import socket
3
+ import subprocess
4
+ import sys
5
+ import traceback
6
+ import urllib.error
7
+ import urllib.request
8
+ from pathlib import Path
9
+
10
+
11
+ class FirewallHandler:
12
+ """Handles firewall detection and configuration for network access."""
13
+
14
+ def __init__(self, logger=None):
15
+ self.logger = logger
16
+ self.test_urls = [
17
+ "http://httpbin.org/get",
18
+ "http://www.google.com",
19
+ "https://httpbin.org/get",
20
+ "https://www.google.com",
21
+ ]
22
+ self.srtm_urls = [
23
+ "https://cloud.sdsc.edu/v1/AUTH_opentopography/Raster/SRTM_GL1/",
24
+ "http://cloud.sdsc.edu/v1/AUTH_opentopography/Raster/SRTM_GL1/",
25
+ ]
26
+
27
+ def check_network_access(self, timeout: int = 5) -> bool:
28
+ """Check if network access is available."""
29
+ self.logger.info("Checking network connectivity...")
30
+
31
+ # First check basic connectivity
32
+ if not self._check_basic_connectivity():
33
+ self.logger.warning("Basic network connectivity failed")
34
+ return False
35
+
36
+ # Then check HTTP access
37
+ if not self._check_http_access(timeout):
38
+ self.logger.warning("HTTP access failed")
39
+ return False
40
+
41
+ # Finally check SRTM-specific URLs
42
+ if not self._check_srtm_access(timeout):
43
+ self.logger.warning("SRTM service access failed")
44
+ return False
45
+
46
+ self.logger.info("Network access verified successfully")
47
+ return True
48
+
49
+ def _check_basic_connectivity(self) -> bool:
50
+ """Check basic network connectivity using socket."""
51
+ try:
52
+ # Try to connect to DNS servers
53
+ for host, port in [("8.8.8.8", 53), ("1.1.1.1", 53)]:
54
+ try:
55
+ with socket.create_connection((host, port), timeout=3):
56
+ return True
57
+ except (TimeoutError, OSError):
58
+ continue
59
+ return False
60
+ except Exception as e:
61
+ self.logger.debug(f"Basic connectivity check failed: {e}")
62
+ return False
63
+
64
+ def _check_http_access(self, timeout: int) -> bool:
65
+ """Check HTTP access to common websites."""
66
+ for url in self.test_urls:
67
+ try:
68
+ with urllib.request.urlopen(url, timeout=timeout) as response:
69
+ if response.status == 200:
70
+ self.logger.debug(f"HTTP access confirmed via {url}")
71
+ return True
72
+ except (TimeoutError, urllib.error.URLError, urllib.error.HTTPError) as e:
73
+ self.logger.debug(f"HTTP access failed for {url}: {e}")
74
+ continue
75
+ return False
76
+
77
+ def _check_srtm_access(self, timeout: int) -> bool:
78
+ """Check access to SRTM-specific URLs."""
79
+ for url in self.srtm_urls:
80
+ try:
81
+ with urllib.request.urlopen(url, timeout=timeout) as response:
82
+ if response.status in [200, 403]: # 403 is expected for directory listing
83
+ self.logger.debug(f"SRTM access confirmed via {url}")
84
+ return True
85
+ except (TimeoutError, urllib.error.URLError, urllib.error.HTTPError) as e:
86
+ self.logger.debug(f"SRTM access failed for {url}: {e}")
87
+ continue
88
+ return False
89
+
90
+ def handle_firewall_issue(self):
91
+ """Handle firewall issues by attempting to create rules and inform user."""
92
+ self.logger.info("Attempting to resolve firewall issues...")
93
+
94
+ # Get current executable path
95
+ exe_path = self._get_executable_path()
96
+ if not exe_path:
97
+ self.logger.error("Could not determine executable path")
98
+ self._show_manual_instructions()
99
+ return
100
+
101
+ # Try to create firewall rules
102
+ if self._is_windows():
103
+ self._handle_windows_firewall(exe_path)
104
+ else:
105
+ self._handle_linux_firewall(exe_path)
106
+
107
+ def _get_executable_path(self) -> str | None:
108
+ """Get the path of the current executable."""
109
+ try:
110
+ if getattr(sys, "frozen", False):
111
+ # PyInstaller executable
112
+ return sys.executable
113
+ else:
114
+ # Python script
115
+ return sys.executable
116
+ except Exception as e:
117
+ self.logger.error(f"Error getting executable path: {e}")
118
+ return None
119
+
120
+ def _is_windows(self) -> bool:
121
+ """Check if running on Windows."""
122
+ return os.name == "nt"
123
+
124
+ def _handle_windows_firewall(self, exe_path: str):
125
+ """Handle Windows firewall configuration."""
126
+ self.logger.info("Attempting to configure Windows Firewall...")
127
+
128
+ app_name = Path(exe_path).stem
129
+
130
+ # Commands to add firewall rules
131
+ commands = [
132
+ # Inbound rule
133
+ [
134
+ "netsh",
135
+ "advfirewall",
136
+ "firewall",
137
+ "add",
138
+ "rule",
139
+ f"name={app_name}_Inbound",
140
+ "dir=in",
141
+ "action=allow",
142
+ f"program={exe_path}",
143
+ "enable=yes",
144
+ ],
145
+ # Outbound rule
146
+ [
147
+ "netsh",
148
+ "advfirewall",
149
+ "firewall",
150
+ "add",
151
+ "rule",
152
+ f"name={app_name}_Outbound",
153
+ "dir=out",
154
+ "action=allow",
155
+ f"program={exe_path}",
156
+ "enable=yes",
157
+ ],
158
+ ]
159
+
160
+ success = False
161
+ for cmd in commands:
162
+ try:
163
+ result = subprocess.run(cmd, capture_output=True, text=True, check=True)
164
+ self.logger.info(
165
+ f"Firewall rule added successfully: {' '.join(cmd)} result: {result}"
166
+ )
167
+ success = True
168
+ except subprocess.CalledProcessError as e:
169
+ self.logger.warning(f"Failed to add firewall rule: {e}")
170
+ self.logger.debug(f"Command: {' '.join(cmd)}")
171
+ self.logger.debug(f"Error output: {e.stderr}")
172
+ except Exception as e:
173
+ self.logger.error(f"Unexpected error adding firewall rule: {e}")
174
+ self.logger.debug(f"Full traceback:\n{traceback.format_exc()}")
175
+
176
+ if success:
177
+ self.logger.info(
178
+ "Windows Firewall rules added successfully. Please restart the application."
179
+ )
180
+ else:
181
+ self.logger.warning("Failed to automatically configure Windows Firewall.")
182
+ self._show_manual_instructions()
183
+
184
+ def _handle_linux_firewall(self, exe_path: str):
185
+ """Handle Linux firewall configuration."""
186
+ self.logger.info("Detected Linux system. Firewall configuration may be needed.")
187
+ self._show_manual_instructions()
188
+
189
+ def _show_manual_instructions(self):
190
+ """Show general manual instructions"""
191
+ self.logger.info(
192
+ "Please check your firewall settings and ensure the application has network access.\n"
193
+ "Refer to the documentation for manual configuration steps."
194
+ "quick solution:"
195
+ "Start your EXE as administrator:"
196
+ "Right-click on EXE → Run as administrator"
197
+ "Or temporarily deactivate the firewall:"
198
+ )
main.py ADDED
@@ -0,0 +1,153 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Unified entry point for CLI and GUI application.
4
+ Automatically detects whether to run CLI or GUI based on how the application is started.
5
+ """
6
+
7
+ import os
8
+ import sys
9
+
10
+
11
+ def is_console_attached():
12
+ """
13
+ Check if the application is running in a console environment.
14
+ Returns True if launched from console, False if launched via double-click.
15
+ """
16
+ try:
17
+ # On Windows, check if we have a console attached
18
+ if os.name == "nt":
19
+ import ctypes
20
+
21
+ kernel32 = ctypes.windll.kernel32
22
+ # GetConsoleWindow returns 0 if no console is attached
23
+ console_window = kernel32.GetConsoleWindow()
24
+ if console_window == 0:
25
+ return False
26
+
27
+ # Check if the console was created by this process
28
+ # (indicates double-click launch with console auto-created)
29
+ process_list = kernel32.GetConsoleProcessList(None, 0)
30
+ if process_list <= 1:
31
+ return False
32
+
33
+ return True
34
+ else:
35
+ # On Unix-like systems (macOS, Linux), check multiple indicators
36
+ # Check if stdout is a terminal
37
+ if not sys.stdout.isatty():
38
+ return False
39
+
40
+ # Additional check for macOS: Check if we're running in a .app bundle
41
+ if sys.platform == "darwin":
42
+ # If we're in a .app bundle, we're likely launched via double-click
43
+ executable_path = sys.executable
44
+ if ".app/" in executable_path:
45
+ # We're in an app bundle, check if we have a real terminal
46
+ # by checking if TERM environment variable is set
47
+ return os.environ.get("TERM") is not None
48
+
49
+ return True
50
+ except Exception as ex:
51
+ # Fallback: assume GUI if we can't determine
52
+ print(ex)
53
+ return False
54
+
55
+
56
+ def has_command_line_args():
57
+ """Check if command line arguments (beyond script name) are provided."""
58
+ return len(sys.argv) > 1
59
+
60
+
61
+ def main():
62
+ """Main entry point that decides between CLI and GUI."""
63
+
64
+ # Force CLI mode if command line arguments are provided
65
+ if has_command_line_args():
66
+ run_cli()
67
+ return
68
+
69
+ # Check if we're in a console environment
70
+ if is_console_attached():
71
+ # We're in a console - offer choice or default to CLI
72
+ print("Python Template Project")
73
+ print("=" * 50)
74
+ print("Detected console environment.")
75
+ print("Options:")
76
+ print(" 1. Run CLI interface (default)")
77
+ print(" 2. Run GUI interface")
78
+ print(" 3. Show help")
79
+ print()
80
+
81
+ try:
82
+ choice = input("Select option [1]: ").strip()
83
+ if choice == "2":
84
+ run_gui()
85
+ elif choice == "3":
86
+ show_help()
87
+ else:
88
+ run_cli()
89
+ except (KeyboardInterrupt, EOFError):
90
+ print("\nExiting...")
91
+ sys.exit(0)
92
+ else:
93
+ # Launched via double-click - start GUI
94
+ run_gui()
95
+
96
+
97
+ def run_cli():
98
+ """Launch the CLI interface."""
99
+ try:
100
+ from python_template_project.cli.cli import main as cli_main
101
+
102
+ cli_main()
103
+ except ImportError as e:
104
+ print(f"Error importing CLI module: {e}")
105
+ sys.exit(1)
106
+ except Exception as e:
107
+ print(f"Error running CLI: {e}")
108
+ sys.exit(1)
109
+
110
+
111
+ def run_gui():
112
+ """Launch the GUI interface."""
113
+ try:
114
+ from python_template_project.gui.gui import main as gui_main
115
+
116
+ gui_main()
117
+ except ImportError as e:
118
+ print(f"Error importing GUI module: {e}")
119
+ # If GUI fails, fallback to CLI
120
+ print("Falling back to CLI interface...")
121
+ run_cli()
122
+ except Exception as e:
123
+ print(f"Error running GUI: {e}")
124
+ print("Falling back to CLI interface...")
125
+ run_cli()
126
+
127
+
128
+ def show_help():
129
+ """Show help information."""
130
+ print("""
131
+ Unified Application
132
+
133
+ Usage:
134
+ When launched from console:
135
+ - Without arguments: Interactive mode selection
136
+ - With arguments: Direct CLI mode
137
+
138
+ When launched via double-click:
139
+ - Automatically starts GUI interface
140
+
141
+ Command Line Arguments:
142
+ Run with any CLI arguments to force CLI mode.
143
+
144
+ Examples:
145
+ python main.py --help # Shows CLI help
146
+ python main.py # Interactive mode selection
147
+ double-click main.exe # Starts GUI
148
+
149
+ """)
150
+
151
+
152
+ if __name__ == "__main__":
153
+ main()
@@ -0,0 +1,21 @@
1
+ # file generated by setuptools-scm
2
+ # don't change, don't track in version control
3
+
4
+ __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
5
+
6
+ TYPE_CHECKING = False
7
+ if TYPE_CHECKING:
8
+ from typing import Tuple
9
+ from typing import Union
10
+
11
+ VERSION_TUPLE = Tuple[Union[int, str], ...]
12
+ else:
13
+ VERSION_TUPLE = object
14
+
15
+ version: str
16
+ __version__: str
17
+ __version_tuple__: VERSION_TUPLE
18
+ version_tuple: VERSION_TUPLE
19
+
20
+ __version__ = version = '0.1.18'
21
+ __version_tuple__ = version_tuple = (0, 1, 18)