pyhabitat 1.0.30__tar.gz → 1.0.32__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.
Potentially problematic release.
This version of pyhabitat might be problematic. Click here for more details.
- {pyhabitat-1.0.30/pyhabitat.egg-info → pyhabitat-1.0.32}/PKG-INFO +6 -2
- {pyhabitat-1.0.30/pyhabitat-build → pyhabitat-1.0.32}/pyhabitat/__init__.py +4 -0
- {pyhabitat-1.0.30/pyhabitat-build → pyhabitat-1.0.32}/pyhabitat/environment.py +104 -15
- pyhabitat-1.0.32/pyhabitat/report.py +0 -0
- {pyhabitat-1.0.30 → pyhabitat-1.0.32/pyhabitat.egg-info}/PKG-INFO +6 -2
- {pyhabitat-1.0.30 → pyhabitat-1.0.32}/pyhabitat.egg-info/SOURCES.txt +1 -0
- {pyhabitat-1.0.30 → pyhabitat-1.0.32}/pyproject.toml +10 -5
- {pyhabitat-1.0.30 → pyhabitat-1.0.32}/LICENSE +0 -0
- {pyhabitat-1.0.30 → pyhabitat-1.0.32}/README.md +0 -0
- {pyhabitat-1.0.30 → pyhabitat-1.0.32}/pyhabitat/cli.py +0 -0
- /pyhabitat-1.0.30/pyhabitat/report.py → /pyhabitat-1.0.32/pyhabitat/demo.py +0 -0
- {pyhabitat-1.0.30 → pyhabitat-1.0.32}/pyhabitat/utils.py +0 -0
- {pyhabitat-1.0.30 → pyhabitat-1.0.32}/pyhabitat-build/__main__.py +0 -0
- {pyhabitat-1.0.30 → pyhabitat-1.0.32/pyhabitat-build}/pyhabitat/__init__.py +0 -0
- {pyhabitat-1.0.30 → pyhabitat-1.0.32}/pyhabitat-build/pyhabitat/cli.py +0 -0
- {pyhabitat-1.0.30 → pyhabitat-1.0.32/pyhabitat-build}/pyhabitat/environment.py +0 -0
- {pyhabitat-1.0.30 → pyhabitat-1.0.32}/pyhabitat-build/pyhabitat/utils.py +0 -0
- {pyhabitat-1.0.30 → pyhabitat-1.0.32}/pyhabitat.egg-info/dependency_links.txt +0 -0
- {pyhabitat-1.0.30 → pyhabitat-1.0.32}/pyhabitat.egg-info/entry_points.txt +0 -0
- {pyhabitat-1.0.30 → pyhabitat-1.0.32}/pyhabitat.egg-info/top_level.txt +0 -0
- {pyhabitat-1.0.30 → pyhabitat-1.0.32}/setup.cfg +0 -0
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyhabitat
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.32
|
|
4
4
|
Summary: A lightweight library for detecting system environment, GUI, and build properties.
|
|
5
5
|
Author-email: George Clayton Bennett <george.bennett@memphistn.gov>
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Keywords: environment,os-detection,gui,build-system
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: Operating System :: OS Independent
|
|
10
|
-
Classifier:
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
|
+
Classifier: Topic :: Utilities
|
|
11
15
|
Requires-Python: >=3.7
|
|
12
16
|
Description-Content-Type: text/markdown
|
|
13
17
|
License-File: LICENSE
|
|
@@ -30,6 +30,8 @@ from .environment import (
|
|
|
30
30
|
user_darrin_deyoung,
|
|
31
31
|
can_read_input,
|
|
32
32
|
can_spawn_shell,
|
|
33
|
+
is_ascii,
|
|
34
|
+
is_binary,
|
|
33
35
|
)
|
|
34
36
|
|
|
35
37
|
# Optional: Set __all__ for explicit documentation and cleaner imports
|
|
@@ -63,6 +65,8 @@ __all__ = [
|
|
|
63
65
|
'user_darrin_deyoung',
|
|
64
66
|
'can_read_input',
|
|
65
67
|
'can_spawn_shell',
|
|
68
|
+
'is_ascii',
|
|
69
|
+
'is_binary',
|
|
66
70
|
]
|
|
67
71
|
|
|
68
72
|
__version__ = get_version()
|
|
@@ -17,6 +17,12 @@ import logging
|
|
|
17
17
|
import getpass
|
|
18
18
|
import select
|
|
19
19
|
|
|
20
|
+
# On Windows, we need the msvcrt module for non-blocking I/O
|
|
21
|
+
try:
|
|
22
|
+
import msvcrt
|
|
23
|
+
except ImportError:
|
|
24
|
+
msvcrt = None
|
|
25
|
+
|
|
20
26
|
__all__ = [
|
|
21
27
|
'matplotlib_is_available_for_gui_plotting',
|
|
22
28
|
'matplotlib_is_available_for_headless_image_export',
|
|
@@ -512,6 +518,19 @@ def is_python_script(path: Path | str | None = None, debug: bool = False, suppre
|
|
|
512
518
|
return False
|
|
513
519
|
return exec_path.suffix.lower() == '.py'
|
|
514
520
|
|
|
521
|
+
# --- File encoding check ---
|
|
522
|
+
def is_binary(path:str|Path|None=None)->bool:
|
|
523
|
+
"""
|
|
524
|
+
Target file is encoded as binary.
|
|
525
|
+
"""
|
|
526
|
+
pass
|
|
527
|
+
|
|
528
|
+
def is_ascii(path:str|Path|None=None)->bool:
|
|
529
|
+
"""
|
|
530
|
+
Target file is encoded as ascii, plaintext.
|
|
531
|
+
"""
|
|
532
|
+
pass
|
|
533
|
+
|
|
515
534
|
# --- Interpreter Check ---
|
|
516
535
|
|
|
517
536
|
def interp_path(debug: bool = False) -> str:
|
|
@@ -543,21 +562,46 @@ def interactive_terminal_is_available():
|
|
|
543
562
|
then typer.prompt() or input() will work reliably,
|
|
544
563
|
without getting lost in a log or lost entirely.
|
|
545
564
|
|
|
565
|
+
Solution correctly identifies that true interactivity requires:
|
|
566
|
+
(1) a TTY (potential) connection
|
|
567
|
+
(2) the ability to execute
|
|
568
|
+
(3) the ability to read I/O
|
|
569
|
+
(4) ignores known limitatons in restrictive environments
|
|
570
|
+
|
|
571
|
+
Jargon:
|
|
572
|
+
A TTY, short for Teletypewriter or TeleTYpe,
|
|
573
|
+
is a conceptual or physical device that serves
|
|
574
|
+
as the interface for a user to interact with
|
|
575
|
+
a computer system.
|
|
546
576
|
"""
|
|
547
577
|
# Address walmart demo unit edge case, fast check, though this might hamstring othwrwise successful processes
|
|
548
|
-
if
|
|
578
|
+
if user_darrin_deyoung():
|
|
549
579
|
return False
|
|
550
|
-
|
|
580
|
+
|
|
581
|
+
# Check if a tty is attached to stdin,
|
|
582
|
+
# quick failure here if not before testing spwaning and reading
|
|
583
|
+
if not (sys.stdin.isatty() and sys.stdout.isatty()):
|
|
584
|
+
return False
|
|
585
|
+
|
|
586
|
+
# Check of a new shell can be launched to print stuff
|
|
551
587
|
if not can_spawn_shell():
|
|
552
588
|
return False
|
|
589
|
+
|
|
553
590
|
# A user can interact with a console, providing input
|
|
554
591
|
#if not can_read_input():
|
|
555
592
|
# return False
|
|
556
|
-
|
|
593
|
+
|
|
557
594
|
return sys.stdin.isatty() and sys.stdout.isatty()
|
|
558
595
|
|
|
559
596
|
def user_darrin_deyoung():
|
|
560
597
|
"""Common demo unit undicator, edge case that is unable to launch terminal"""
|
|
598
|
+
# Enable teating on non-Windows, non-demo systems
|
|
599
|
+
# where this function would otherwise return False.
|
|
600
|
+
# Linux: `export USER_DARRIN_DEYOUNG=True`
|
|
601
|
+
if os.getenv('USER_DARRIN_DEYOUNG','').lower() == "true":
|
|
602
|
+
print("env var USER_DARRIN_DEYOUNG is set to True.")
|
|
603
|
+
return True
|
|
604
|
+
# Darrin Deyoung is the typical username on demo-mode Windows systems
|
|
561
605
|
if not on_windows():
|
|
562
606
|
return False
|
|
563
607
|
username = getpass.getuser()
|
|
@@ -568,25 +612,33 @@ def can_spawn_shell(override_known:bool=False)->bool:
|
|
|
568
612
|
global _CAN_SPAWN_SHELL
|
|
569
613
|
if _CAN_SPAWN_SHELL is not None and override_known is False:
|
|
570
614
|
return _CAN_SPAWN_SHELL
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
615
|
+
|
|
616
|
+
try:
|
|
617
|
+
# Use a simple, universally applicable command with shell=True
|
|
618
|
+
# 'true' on Linux/macOS, or a basic command on Windows via cmd.exe
|
|
619
|
+
# A simple 'echo' or 'exit 0' would also work
|
|
620
|
+
result = subprocess.run(
|
|
621
|
+
'exit 0', # A shell-internal command that succeeds on most shells
|
|
622
|
+
stdout=subprocess.PIPE,
|
|
623
|
+
stderr=subprocess.PIPE,
|
|
624
|
+
timeout=2,
|
|
625
|
+
shell=True # <--- ESSENTIAL for cross-platform reliability
|
|
626
|
+
)
|
|
577
627
|
|
|
578
|
-
|
|
628
|
+
_CAN_SPAWN_SHELL = result.returncode == 0
|
|
629
|
+
return _CAN_SPAWN_SHELL
|
|
630
|
+
|
|
579
631
|
except subprocess.TimeoutExpired:
|
|
580
|
-
|
|
632
|
+
print("Shell spawn failed: TimeoutExpired")
|
|
581
633
|
_CAN_SPAWN_SHELL = result.returncode == 0
|
|
582
634
|
return _CAN_SPAWN_SHELL
|
|
583
635
|
except subprocess.SubprocessError:
|
|
584
|
-
|
|
636
|
+
print("Shell spawn failed: SubprocessError")
|
|
585
637
|
_CAN_SPAWN_SHELL = False
|
|
586
638
|
return False
|
|
587
639
|
except OSError:
|
|
588
640
|
_CAN_SPAWN_SHELL = False
|
|
589
|
-
|
|
641
|
+
print("Shell spawn failed: OSError (likely permission or missing binary)")
|
|
590
642
|
return False
|
|
591
643
|
|
|
592
644
|
def can_read_input(override_known:bool=False)-> bool:
|
|
@@ -594,10 +646,43 @@ def can_read_input(override_known:bool=False)-> bool:
|
|
|
594
646
|
global _CAN_READ_INPUT
|
|
595
647
|
if _CAN_READ_INPUT is not None and override_known is False:
|
|
596
648
|
return _CAN_READ_INPUT
|
|
649
|
+
|
|
650
|
+
# --- 1. Windows Specific Check (msvcrt) ---
|
|
651
|
+
if msvcrt is not None and sys.stdin.isatty():
|
|
652
|
+
try:
|
|
653
|
+
# msvcrt.kbhit() checks if a keyboard hit is present
|
|
654
|
+
# We don't read the input yet, just check if it's there
|
|
655
|
+
_CAN_READ_INPUT = msvcrt.kbhit()
|
|
656
|
+
# If kbhit returns True, it means a key press is waiting.
|
|
657
|
+
# We assume if the terminal *is* a TTY, it *can* read input.
|
|
658
|
+
# We can't actually call input() without blocking, so we check TTY instead.
|
|
659
|
+
if _CAN_READ_INPUT:
|
|
660
|
+
return True
|
|
661
|
+
|
|
662
|
+
# Since we are checking if a *user can* interact, if we are in a TTY,
|
|
663
|
+
# we assume the capability exists, even if nothing is currently buffered.
|
|
664
|
+
# This prevents the false negative when no key is pressed.
|
|
665
|
+
_CAN_READ_INPUT = True
|
|
666
|
+
return True
|
|
667
|
+
|
|
668
|
+
except Exception as e:
|
|
669
|
+
# Catch errors in the kbhit check itself
|
|
670
|
+
logging.debug(f"msvcrt check failed: {e}")
|
|
671
|
+
pass # Fall through to the select check
|
|
672
|
+
|
|
673
|
+
# --- 2. POSIX/General Check (select) ---
|
|
674
|
+
# This block is reliable on Linux/macOS and other POSIX systems.
|
|
597
675
|
try:
|
|
598
|
-
#
|
|
676
|
+
# _CAN_READ_INPUT is assigned the read-ready list ([] or [sys.stdin])
|
|
677
|
+
# The return value is then the boolean conversion of that list's truthiness.
|
|
678
|
+
# 1. select.select(...) returns a 3-element tuple.
|
|
679
|
+
# 2. [0] gets the read-ready list (rlist).
|
|
680
|
+
# 3. Wrapping the result in bool() converts the list's truth value:
|
|
681
|
+
# - [] becomes False
|
|
682
|
+
# - [sys.stdin] becomes True
|
|
599
683
|
_CAN_READ_INPUT = select.select([sys.stdin], [], [], 0.1)[0]
|
|
600
|
-
|
|
684
|
+
# Return the boolean value of the list: True if [sys.stdin], False if []
|
|
685
|
+
return bool(_CAN_READ_INPUT) # <--- Requied to convert list to boolean
|
|
601
686
|
except ValueError:
|
|
602
687
|
logging.debug("Input check failed: ValueError (invalid file descriptor)")
|
|
603
688
|
_CAN_READ_INPUT = False
|
|
@@ -606,6 +691,9 @@ def can_read_input(override_known:bool=False)-> bool:
|
|
|
606
691
|
logging.debug("Input check failed: OSError (likely I/O issue)")
|
|
607
692
|
_CAN_READ_INPUT = False
|
|
608
693
|
return False
|
|
694
|
+
|
|
695
|
+
# Final fallback: if nothing worked, assume False
|
|
696
|
+
return False
|
|
609
697
|
|
|
610
698
|
# --- Browser Check ---
|
|
611
699
|
def web_browser_is_available() -> bool:
|
|
@@ -623,6 +711,7 @@ def web_browser_is_available() -> bool:
|
|
|
623
711
|
if shutil.which("xdg-open"):
|
|
624
712
|
return True
|
|
625
713
|
return False
|
|
714
|
+
|
|
626
715
|
|
|
627
716
|
# --- LAUNCH MECHANISMS BASED ON ENVIRONMENT ---
|
|
628
717
|
def edit_textfile(path: Path | str | None = None) -> None:
|
|
File without changes
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyhabitat
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.32
|
|
4
4
|
Summary: A lightweight library for detecting system environment, GUI, and build properties.
|
|
5
5
|
Author-email: George Clayton Bennett <george.bennett@memphistn.gov>
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Keywords: environment,os-detection,gui,build-system
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: Operating System :: OS Independent
|
|
10
|
-
Classifier:
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
|
+
Classifier: Topic :: Utilities
|
|
11
15
|
Requires-Python: >=3.7
|
|
12
16
|
Description-Content-Type: text/markdown
|
|
13
17
|
License-File: LICENSE
|
|
@@ -6,21 +6,26 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "pyhabitat"
|
|
9
|
-
version = "1.0.
|
|
10
|
-
#dynamic = ["version"]
|
|
9
|
+
version = "1.0.32"
|
|
10
|
+
#dynamic = ["version"]
|
|
11
11
|
authors = [
|
|
12
12
|
{ name="George Clayton Bennett", email="george.bennett@memphistn.gov" },
|
|
13
13
|
]
|
|
14
14
|
description = "A lightweight library for detecting system environment, GUI, and build properties."
|
|
15
15
|
readme = "README.md"
|
|
16
16
|
requires-python = ">=3.7"
|
|
17
|
-
license = "MIT"
|
|
17
|
+
license = "MIT"
|
|
18
18
|
keywords = ["environment", "os-detection", "gui", "build-system"]
|
|
19
|
-
classifiers
|
|
19
|
+
classifiers=[
|
|
20
20
|
"Programming Language :: Python :: 3",
|
|
21
21
|
"Operating System :: OS Independent",
|
|
22
|
-
"
|
|
22
|
+
"Intended Audience :: Developers",
|
|
23
|
+
"Environment :: Console",
|
|
24
|
+
"Topic :: Software Development :: Build Tools",
|
|
25
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
26
|
+
"Topic :: Utilities",
|
|
23
27
|
]
|
|
28
|
+
|
|
24
29
|
dependencies = []
|
|
25
30
|
|
|
26
31
|
[project.scripts]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|