pyhabitat 1.0.18__py3-none-any.whl → 1.0.19__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.

Potentially problematic release.


This version of pyhabitat might be problematic. Click here for more details.

pyhabitat/__init__.py CHANGED
@@ -5,12 +5,14 @@ from .environment import (
5
5
  matplotlib_is_available_for_headless_image_export,
6
6
  tkinter_is_available,
7
7
  in_repl,
8
- on_termux,
9
8
  on_freebsd,
10
9
  on_linux,
11
10
  on_android,
12
11
  on_windows,
12
+ on_wsl,
13
13
  on_apple,
14
+ on_termux,
15
+ on_pydroid,
14
16
  on_ish_alpine,
15
17
  as_pyinstaller,
16
18
  as_frozen,
@@ -34,6 +36,8 @@ __all__ = [
34
36
  'tkinter_is_available',
35
37
  'in_repl',
36
38
  'on_termux',
39
+ 'on_pydroid',
40
+ 'on_wsl',
37
41
  'on_freebsd',
38
42
  'on_linux',
39
43
  'on_android',
pyhabitat/__main__.py CHANGED
@@ -1,4 +1,4 @@
1
- from .cli import run_cli
1
+ from pyhabitat.cli import run_cli
2
2
 
3
3
  if __name__ == "__main__":
4
4
  run_cli()
pyhabitat/cli.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import argparse
2
2
  from pathlib import Path
3
- from . import main
3
+ from pyhabitat.environment import main
4
4
 
5
5
  def run_cli():
6
6
  """Parse CLI arguments and run the pyhabitat environment report."""
pyhabitat/environment.py CHANGED
@@ -22,8 +22,10 @@ __all__ = [
22
22
  'on_termux',
23
23
  'on_freebsd',
24
24
  'on_linux',
25
+ 'on_pydroid',
25
26
  'on_android',
26
27
  'on_windows',
28
+ 'on_wsl',
27
29
  'on_apple',
28
30
  'on_ish_alpine',
29
31
  'as_pyinstaller',
@@ -209,6 +211,64 @@ def on_android() -> bool:
209
211
  return False
210
212
  return "android" in platform.platform().lower()
211
213
 
214
+
215
+ def on_wsl():
216
+ """Return True if running inside Windows Subsystem for Linux (WSL or WSL2)."""
217
+ # Must look like Linux, not Windows
218
+ if platform.system() != "Linux":
219
+ return False
220
+
221
+
222
+ # --- Check environment variables for WSL2 ---
223
+ # False negative risk:
224
+ # Environment variables may be absent in older WSL1 installs.
225
+ # False negative likelihood: low.
226
+ if "WSL_DISTRO_NAME" in os.environ or "WSL_INTEROP" in os.environ:
227
+ return True
228
+
229
+ # --- Check kernel info for 'microsoft' string ---
230
+ # False negative risk:
231
+ # Custom kernels, future Windows versions, or minimal WSL distros may omit 'microsoft' in strings.
232
+ # False negative likelihood: Very low to moderate.
233
+
234
+ try:
235
+ with open("/proc/version") as f:
236
+ if "microsoft" in version_info or "wsl" in version_info:
237
+ return True
238
+ except FileNotFoundError:
239
+ pass
240
+
241
+ # Check for WSL-specific mounts (fallback)
242
+ """
243
+ /proc/sys/kernel/osrelease
244
+ Purpose: Contains the kernel release string. In WSL, it usually contains "microsoft" (WSL2) or "microsoft-standard" (WSL1).
245
+ Very reliable for detecting WSL1 and WSL2 unless someone compiled a custom kernel and removed the microsoft string.
246
+
247
+ False negative risk:
248
+ If /proc/version or /proc/sys/kernel/osrelease cannot be read due to permissions, a containerized WSL distro, or some sandboxed environment.
249
+ # False negative likelihood: Very low.
250
+ """
251
+ if Path("/proc/sys/kernel/osrelease").exists():
252
+ try:
253
+ with open("/proc/sys/kernel/osrelease") as f:
254
+ osrelease = f.read().lower()
255
+ if "microsoft" in osrelease:
256
+ return True
257
+ except Exception:
258
+ pass
259
+ return False
260
+
261
+ def on_pydroid():
262
+ """Return True if running under Pydroid 3 (Android app)."""
263
+ if not on_android():
264
+ return False
265
+
266
+ exe = (sys.executable or "").lower()
267
+ if "pydroid" in exe or "ru.iiec.pydroid3" in exe:
268
+ return True
269
+
270
+ return any("pydroid" in p.lower() for p in sys.path)
271
+
212
272
  def on_windows() -> bool:
213
273
  """Detect if running on Windows."""
214
274
  return platform.system() == 'Windows'
@@ -277,31 +337,29 @@ def as_frozen():
277
337
  return getattr(sys, 'frozen', False)
278
338
 
279
339
  # --- Binary Characteristic Checks ---
280
- def is_elf(exec_path: Path | str | None = None, debug: bool = False) -> bool:
340
+ def is_elf(exec_path: Path | str | None = None, debug: bool = False, suppress_debug: bool =False) -> bool:
281
341
  """Checks if the currently running executable (sys.argv[0]) is a standalone PyInstaller-built ELF binary."""
282
342
  # If it's a pipx installation, it is not the monolithic binary we are concerned with here.
283
- exec_path, is_valid = _check_executable_path(exec_path, debug)
343
+ exec_path, is_valid = _check_executable_path(exec_path, debug and not suppress_debug)
284
344
  if not is_valid:
285
345
  return False
286
346
 
287
347
  try:
288
348
  # Check the magic number: The first four bytes of an ELF file are 0x7f, 'E', 'L', 'F' (b'\x7fELF').
289
349
  # This is the most reliable way to determine if the executable is a native binary wrapper (like PyInstaller's).
290
- with open(exec_path, 'rb') as f:
291
- magic_bytes = f.read(4)
292
- if debug:
293
- logging.debug(f"Magic bytes: {magic_bytes}")
350
+ magic_bytes = read_magic_bytes(exec_path, 4, debug and not suppress_debug)
351
+
294
352
  return magic_bytes == b'\x7fELF'
295
353
  except Exception:
296
354
  if debug:
297
355
  logging.debug("False (Exception during file check)")
298
356
  return False
299
357
 
300
- def is_pyz(exec_path: Path | str | None = None, debug: bool = False) -> bool:
358
+ def is_pyz(exec_path: Path | str | None = None, debug: bool = False, suppress_debug: bool =False) -> bool:
301
359
  """Checks if the currently running executable (sys.argv[0]) is a PYZ zipapp ."""
302
360
 
303
361
  # If it's a pipx installation, it is not the monolithic binary we are concerned with here.
304
- exec_path, is_valid = _check_executable_path(exec_path, debug)
362
+ exec_path, is_valid = _check_executable_path(exec_path, debug and not suppress_debug)
305
363
  if not is_valid:
306
364
  return False
307
365
 
@@ -319,40 +377,34 @@ def is_pyz(exec_path: Path | str | None = None, debug: bool = False) -> bool:
319
377
  return True
320
378
 
321
379
 
322
- def is_windows_portable_executable(exec_path: Path | str | None = None, debug: bool = False) -> bool:
380
+ def is_windows_portable_executable(exec_path: Path | str | None = None, debug: bool = False, suppress_debug: bool =False) -> bool:
323
381
  """
324
382
  Checks if the specified path or sys.argv[0] is a Windows Portable Executable (PE) binary.
325
383
  Windows Portable Executables include .exe, .dll, and other binaries.
326
384
  The standard way to check for a PE is to look for the MZ magic number at the very beginning of the file.
327
385
  """
328
- exec_path, is_valid = _check_executable_path(exec_path, debug)
386
+ exec_path, is_valid = _check_executable_path(exec_path, debug and not suppress_debug)
329
387
  if not is_valid:
330
388
  return False
331
- try:
332
- with open(exec_path, 'rb') as f:
333
- magic_bytes = f.read(2)
334
- if debug:
335
- logging.debug(f"Magic bytes: {magic_bytes}")
336
- return magic_bytes == b'MZ'
337
- except Exception as e:
338
- if debug:
339
- logging.debug(f"False (Error during file check: {e})")
340
- return False
341
-
342
- def is_macos_executable(exec_path: Path | str | None = None, debug: bool = False) -> bool:
389
+ magic_bytes = read_magic_bytes(exec_path, 2, debug and not suppress_debug)
390
+ result = magic_bytes.startswith(b"MZ")
391
+
392
+ return result
393
+
394
+ def is_macos_executable(exec_path: Path | str | None = None, debug: bool = False, suppress_debug: bool =False) -> bool:
343
395
  """
344
396
  Checks if the currently running executable is a macOS/Darwin Mach-O binary,
345
397
  and explicitly excludes pipx-managed environments.
346
398
  """
347
- exec_path, is_valid = _check_executable_path(exec_path, debug)
399
+ exec_path, is_valid = _check_executable_path(exec_path, debug and not suppress_debug)
348
400
  if not is_valid:
349
401
  return False
350
402
 
351
403
  try:
352
404
  # Check the magic number: Mach-O binaries start with specific 4-byte headers.
353
405
  # Common ones are: b'\xfe\xed\xfa\xce' (32-bit) or b'\xfe\xed\xfa\xcf' (64-bit)
354
- with open(exec_path, 'rb') as f:
355
- magic_bytes = f.read(4)
406
+
407
+ magic_bytes = read_magic_bytes(exec_path, 4, debug and not suppress_debug)
356
408
 
357
409
  # Common Mach-O magic numbers (including their reversed-byte counterparts)
358
410
  MACHO_MAGIC = {
@@ -364,8 +416,6 @@ def is_macos_executable(exec_path: Path | str | None = None, debug: bool = False
364
416
 
365
417
  is_macho = magic_bytes in MACHO_MAGIC
366
418
 
367
- if debug:
368
- logging.debug(f"Magic bytes: {magic_bytes}")
369
419
 
370
420
  return is_macho
371
421
 
@@ -374,9 +424,9 @@ def is_macos_executable(exec_path: Path | str | None = None, debug: bool = False
374
424
  logging.debug("False (Exception during file check)")
375
425
  return False
376
426
 
377
- def is_pipx(exec_path: Path | str | None = None, debug: bool = False) -> bool:
427
+ def is_pipx(exec_path: Path | str | None = None, debug: bool = False, suppress_debug: bool = True) -> bool:
378
428
  """Checks if the executable is running from a pipx managed environment."""
379
- exec_path, is_valid = _check_executable_path(exec_path, debug, check_pipx=False)
429
+ exec_path, is_valid = _check_executable_path(exec_path, debug and not suppress_debug, check_pipx=False)
380
430
  if not is_valid:
381
431
  return False
382
432
 
@@ -392,8 +442,11 @@ def is_pipx(exec_path: Path | str | None = None, debug: bool = False) -> bool:
392
442
  logging.debug(f"INTERP_PATH: {interpreter_path}")
393
443
  logging.debug(f"PIPX_BIN_PATH: {pipx_bin_path}")
394
444
  logging.debug(f"PIPX_VENV_BASE: {pipx_venv_base_path}")
395
- logging.debug(f"Check B result: {norm_interp_path.startswith(str(pipx_venv_base_path).lower())}")
396
-
445
+ is_in_pipx_venv_base = norm_interp_path.startswith(str(pipx_venv_base_path).lower())
446
+ logging.debug(f"Interpreter path resides somewhere within the pipx venv base hierarchy: {is_in_pipx_venv_base}")
447
+ logging.debug(
448
+ f"This determines whether the current interpreter is managed by pipx: {is_in_pipx_venv_base}"
449
+ )
397
450
  if "pipx/venvs" in norm_exec_path or "pipx/venvs" in norm_interp_path:
398
451
  if debug:
399
452
  logging.debug("True (Signature Check)")
@@ -409,8 +462,6 @@ def is_pipx(exec_path: Path | str | None = None, debug: bool = False) -> bool:
409
462
  logging.debug("True (Executable Base Check)")
410
463
  return True
411
464
 
412
- if debug:
413
- logging.debug("False")
414
465
  return False
415
466
  except Exception:
416
467
  if debug:
@@ -445,7 +496,8 @@ def is_pipx(exec_path: Path | str | None = None, debug: bool = False) -> bool:
445
496
  if debug:
446
497
  logging.debug("False (Exception during pipx check)")
447
498
  return False
448
- def is_python_script(path: Path | str | None = None, debug: bool = False) -> bool:
499
+
500
+ def is_python_script(path: Path | str | None = None, debug: bool = False, suppress_debug: bool =False) -> bool:
449
501
  """
450
502
  Checks if the specified path or running script is a Python source file (.py).
451
503
 
@@ -459,14 +511,14 @@ def is_python_script(path: Path | str | None = None, debug: bool = False) -> boo
459
511
  Returns:
460
512
  bool: True if the specified or default path is a Python source file (.py); False otherwise.
461
513
  """
462
- exec_path, is_valid = _check_executable_path(path, debug, check_pipx=False)
514
+ exec_path, is_valid = _check_executable_path(path, debug and not suppress_debug, check_pipx=False)
463
515
  if not is_valid:
464
516
  return False
465
517
  return exec_path.suffix.lower() == '.py'
466
518
 
467
519
  # --- Interpreter Check ---
468
520
 
469
- def interp_path(print_path: bool = False) -> str:
521
+ def interp_path(debug: bool = False) -> str:
470
522
  """
471
523
  Returns the path to the Python interpreter binary and optionally prints it.
472
524
 
@@ -482,8 +534,8 @@ def interp_path(print_path: bool = False) -> str:
482
534
  str: The path to the Python interpreter binary, or an empty string if unavailable.
483
535
  """
484
536
  path = sys.executable
485
- if print_path:
486
- print(f"Python interpreter path: {path}")
537
+ if debug:
538
+ logging.debug(f"Python interpreter path: {path}")
487
539
  return path
488
540
 
489
541
  # --- TTY Check ---
@@ -580,7 +632,20 @@ def _run_dos2unix(path: Path | str | None = None):
580
632
  except Exception:
581
633
  # Catch other subprocess errors (e.g. permission issues)
582
634
  pass
583
-
635
+
636
+ def read_magic_bytes(path: str, length: int = 4, debug: bool = False) -> bytes:
637
+ """Return the first few bytes of a file for type detection."""
638
+ try:
639
+ with open(path, "rb") as f:
640
+ magic = f.read(length)
641
+ if debug:
642
+ logging.debug(f"Magic bytes: {magic!r}")
643
+ return magic
644
+ except Exception as e:
645
+ if debug:
646
+ logging.debug(f"False (Error during file check: {e})")
647
+ return False
648
+
584
649
  def _get_pipx_paths():
585
650
  """
586
651
  Returns the configured/default pipx binary and home directories.
@@ -659,21 +724,26 @@ def main(path=None, debug=False):
659
724
  if debug:
660
725
  logging.basicConfig(level=logging.DEBUG)
661
726
  logging.getLogger('matplotlib').setLevel(logging.WARNING) # Suppress matplotlib debug logs
662
- print("PyHabitat Environment Report")
663
- print("===========================")
664
- print("\nCurrent Build Checks // Based on hasattr(sys,..) and getattr(sys,..)")
727
+ print("================================")
728
+ print("======= PyHabitat Report =======")
729
+ print("================================")
730
+ print("\nCurrent Build Checks ")
731
+ print("# // Based on hasattr(sys,..) and getattr(sys,..)")
665
732
  print("------------------------------")
666
733
  print(f"in_repl(): {in_repl()}")
667
734
  print(f"as_frozen(): {as_frozen()}")
668
735
  print(f"as_pyinstaller(): {as_pyinstaller()}")
669
- print("\nOperating System Checks // Based on platform.system()")
736
+ print("\nOperating System Checks")
737
+ print("# // Based on platform.system()")
670
738
  print("------------------------------")
671
- print(f"on_termux(): {on_termux()}")
672
739
  print(f"on_windows(): {on_windows()}")
673
740
  print(f"on_apple(): {on_apple()}")
674
741
  print(f"on_linux(): {on_linux()}")
675
- print(f"on_ish_alpine(): {on_ish_alpine()}")
742
+ print(f"on_wsl(): {on_wsl()}")
676
743
  print(f"on_android(): {on_android()}")
744
+ print(f"on_termux(): {on_termux()}")
745
+ print(f"on_pydroid(): {on_pydroid()}")
746
+ print(f"on_ish_alpine(): {on_ish_alpine()}")
677
747
  print(f"on_freebsd(): {on_freebsd()}")
678
748
  print("\nCapability Checks")
679
749
  print("-------------------------")
@@ -682,16 +752,27 @@ def main(path=None, debug=False):
682
752
  print(f"matplotlib_is_available_for_headless_image_export(): {matplotlib_is_available_for_headless_image_export()}")
683
753
  print(f"web_browser_is_available(): {web_browser_is_available()}")
684
754
  print(f"interactive_terminal_is_available(): {interactive_terminal_is_available()}")
685
- print("\nInterpreter Checks // Based on sys.executable()")
755
+ print("\nInterpreter Checks")
756
+ print("# // Based on sys.executable()")
686
757
  print("-----------------------------")
687
758
  print(f"interp_path(): {interp_path()}")
688
- print(f"is_elf(interp_path()): {is_elf(interp_path(), debug=debug)}")
689
- print(f"is_windows_portable_executable(interp_path()): {is_windows_portable_executable(interp_path(), debug=debug)}")
690
- print(f"is_macos_executable(interp_path()): {is_macos_executable(interp_path(), debug=debug)}")
691
- print(f"is_pyz(interp_path()): {is_pyz(interp_path(), debug=debug)}")
692
- print(f"is_pipx(interp_path()): {is_pipx(interp_path(), debug=debug)}")
693
- print(f"is_python_script(interp_path()): {is_python_script(interp_path(), debug=debug)}")
694
- print("\nCurrent Environment Check // Based on sys.argv[0]")
759
+ if debug:
760
+ # Do these debug prints once to avoid redundant prints
761
+ # Supress redundant prints explicity using suppress_debug=True,
762
+ # so that only unique information gets printed for each check,
763
+ # even when more than one use the same functions which include debugging logs.
764
+ #print(f"_check_executable_path(interp_path(), debug=True)")
765
+ _check_executable_path(interp_path(), debug=debug)
766
+ #print(f"read_magic_bites(interp_path(), debug=True)")
767
+ read_magic_bytes(interp_path(), debug=debug)
768
+ print(f"is_elf(interp_path()): {is_elf(interp_path(), debug=debug, suppress_debug=True)}")
769
+ print(f"is_windows_portable_executable(interp_path()): {is_windows_portable_executable(interp_path(), debug=debug, suppress_debug=True)}")
770
+ print(f"is_macos_executable(interp_path()): {is_macos_executable(interp_path(), debug=debug, suppress_debug=True)}")
771
+ print(f"is_pyz(interp_path()): {is_pyz(interp_path(), debug=debug, suppress_debug=True)}")
772
+ print(f"is_pipx(interp_path()): {is_pipx(interp_path(), debug=debug, suppress_debug=True)}")
773
+ print(f"is_python_script(interp_path()): {is_python_script(interp_path(), debug=debug, suppress_debug=True)}")
774
+ print("\nCurrent Environment Check")
775
+ print("# // Based on sys.argv[0]")
695
776
  print("-----------------------------")
696
777
  inspect_path = path if path is not None else (None if sys.argv[0] == '-c' else sys.argv[0])
697
778
  logging.debug(f"Inspecting path: {inspect_path}")
@@ -706,13 +787,35 @@ def main(path=None, debug=False):
706
787
  script_path = None
707
788
  if path or (sys.argv[0] and sys.argv[0] != '-c'):
708
789
  script_path = Path(path or sys.argv[0]).resolve()
709
- logging.debug(f"Script path resolved: {script_path}")
790
+ print(f"sys.argv[0] = {str(sys.argv[0])}")
710
791
  if script_path is not None:
711
- print(f"is_elf(): {is_elf(script_path, debug=debug)}")
712
- print(f"is_windows_portable_executable(): {is_windows_portable_executable(script_path, debug=debug)}")
713
- print(f"is_macos_executable(): {is_macos_executable(script_path, debug=debug)}")
714
- print(f"is_pyz(): {is_pyz(script_path, debug=debug)}")
715
- print(f"is_pipx(): {is_pipx(script_path, debug=debug)}")
716
- print(f"is_python_script(): {is_python_script(script_path, debug=debug)}")
792
+ print(f"script_path = {script_path}")
793
+ if debug:
794
+ # Do these debug prints once to avoid redundant prints
795
+ # Supress redundant prints explicity using suppress_debug=True,
796
+ # so that only unique information gets printed for each check,
797
+ # even when more than one use the same functions which include debugging logs.
798
+ p#rint(f"_check_executable_path(script_path, debug=True)")
799
+ _check_executable_path(script_path, debug=debug)
800
+ #print(f"read_magic_bites(script_path, debug=True)")
801
+ read_magic_bytes(script_path, debug=debug)
802
+ print(f"is_elf(): {is_elf(script_path, debug=debug, suppress_debug=True)}")
803
+ print(f"is_windows_portable_executable(): {is_windows_portable_executable(script_path, debug=debug, suppress_debug=True)}")
804
+ print(f"is_macos_executable(): {is_macos_executable(script_path, debug=debug, suppress_debug=True)}")
805
+ print(f"is_pyz(): {is_pyz(script_path, debug=debug, suppress_debug=True)}")
806
+ print(f"is_pipx(): {is_pipx(script_path, debug=debug, suppress_debug=True)}")
807
+ print(f"is_python_script(): {is_python_script(script_path, debug=debug, suppress_debug=True)}")
717
808
  else:
718
- print("script_path is None")
809
+ print("Skipping: ")
810
+ print(" is_elf(), ")
811
+ print(" is_windows_portable_executable(), ")
812
+ print(" is_macos_executable(), ")
813
+ print(" is_pyz(), ")
814
+ print(" is_pipx(), ")
815
+ print(" is_python_script(), ")
816
+ print("All False, script_path is None.")
817
+ print("")
818
+ print("=================================")
819
+ print("=== PyHabitat Report Complete ===")
820
+ print("=================================")
821
+ print("")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyhabitat
3
- Version: 1.0.18
3
+ Version: 1.0.19
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
@@ -78,10 +78,12 @@ Key question: "What is this running on?"
78
78
  | `on_windows()` | Returns `True` on Windows. |
79
79
  | `on_apple()` | Returns `True` on macOS (Darwin). |
80
80
  | `on_linux()` | Returns `True` on Linux in general. |
81
+ | `on_wsl()` | Returns `True` if running inside Windows Subsystem for Linux (WSL or WSL2). |
81
82
  | `on_termux()` | Returns `True` if running in the Termux Android environment. |
82
83
  | `on_freebsd()` | Returns `True` on FreeBSD. |
83
84
  | `on_ish_alpine()` | Returns `True` if running in the iSH Alpine Linux iOS emulator. |
84
85
  | `on_android()` | Returns `True` on any Android-based Linux environment. |
86
+ | `on_pydroid()` | Returns `True` Return True if running under the Pydroid 3 Android app (other versions untested). |
85
87
  | `in_repl()` | Returns `True` is the user is currently in a Python REPL; hasattr(sys,'ps1'). |
86
88
 
87
89
  ### Packaging and Build Checking
@@ -118,7 +120,7 @@ Key Question: "What could I do next?"
118
120
  | Function | Description |
119
121
  | :--- | :--- |
120
122
  | `edit_textfile(path)` | Opens a text file for editing using the default editor (Windows, Linux, macOS) or nano in Termux/iSH. In REPL mode, prints an error. Path argument (str or Path) uses Path.resolve() for stability. |
121
- | `interp_path(print_path=False)` | Returns the path to the Python interpreter binary (sys.executable). Optionally prints the path. Returns empty string if unavailable. |
123
+ | `interp_path()` | Returns the path to the Python interpreter binary (sys.executable). Returns empty string if unavailable. |
122
124
  | `main()` | Prints a comprehensive environment report with sections: Interpreter Checks (sys.executable), Current Environment Check (sys.argv[0]), Current Build Checks (sys attributes), Operating System Checks (platform.system()), and Capability Checks. Run via `python -m pyhabitat` or `import pyhabitat; pyhabitat.main()` in the REPL. |
123
125
 
124
126
  </details>
@@ -0,0 +1,11 @@
1
+ pyhabitat/__init__.py,sha256=B_yS2yBG2kjHkte_xissSG8aJ15af-soBo3Cy7caiEc,1288
2
+ pyhabitat/__main__.py,sha256=qlOKShd_Xk0HGpYOySXQSQe3K60a9wwrstCAceJkKIs,76
3
+ pyhabitat/__main__stable.py,sha256=UACpHLrr_Rmf0L5dJCEae6kFzLn7dqCqIri68IBnb10,2910
4
+ pyhabitat/cli.py,sha256=ZlY6v_IT7Mw-ekR3WPT8NLsqMQ_RXI-cckVq9oLT4AU,683
5
+ pyhabitat/environment.py,sha256=2wyjdWNRSv8VxaXkjoQz285ATAlhddrY_dor45mMnQ4,32871
6
+ pyhabitat-1.0.19.dist-info/licenses/LICENSE,sha256=D4fg30ctUGnCJlWu3ONv5-V8JE1v3ctakoJTcVjsJlg,1072
7
+ pyhabitat-1.0.19.dist-info/METADATA,sha256=N8o0nM2KOq7X4B-JNUMcePtqjinqsdqrqZ11Ct8qsRY,10900
8
+ pyhabitat-1.0.19.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
9
+ pyhabitat-1.0.19.dist-info/entry_points.txt,sha256=409xZ-BrarQJJLtO-aActCGkL0FMhNVi9wsq3u7tRHM,52
10
+ pyhabitat-1.0.19.dist-info/top_level.txt,sha256=zXYK44Qu8EqxUETREvd2diMUaB5JiGRErkwFaoLQnnI,10
11
+ pyhabitat-1.0.19.dist-info/RECORD,,
@@ -1,11 +0,0 @@
1
- pyhabitat/__init__.py,sha256=GcpHBpfEer9O9dKBUREU1RTd5w0im9ph5ew4bs7jOvY,1228
2
- pyhabitat/__main__.py,sha256=hhH17lkw-ZalKp9NolnPGwW0KYxbXirspWvhBKNyBks,67
3
- pyhabitat/__main__stable.py,sha256=UACpHLrr_Rmf0L5dJCEae6kFzLn7dqCqIri68IBnb10,2910
4
- pyhabitat/cli.py,sha256=vuRczazuumIaJl4Td2VvCR5lXcKKNH90V8Yx0KZUJck,663
5
- pyhabitat/environment.py,sha256=7yXMCHvTRkfwwQnsgzrDXPDG9m8h8yhI5oCNlJTHWUA,28026
6
- pyhabitat-1.0.18.dist-info/licenses/LICENSE,sha256=D4fg30ctUGnCJlWu3ONv5-V8JE1v3ctakoJTcVjsJlg,1072
7
- pyhabitat-1.0.18.dist-info/METADATA,sha256=Xk4blTODZGW6NiuqN5e33SuePkTb-PnNU5pGGzeHXvs,10733
8
- pyhabitat-1.0.18.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
9
- pyhabitat-1.0.18.dist-info/entry_points.txt,sha256=409xZ-BrarQJJLtO-aActCGkL0FMhNVi9wsq3u7tRHM,52
10
- pyhabitat-1.0.18.dist-info/top_level.txt,sha256=zXYK44Qu8EqxUETREvd2diMUaB5JiGRErkwFaoLQnnI,10
11
- pyhabitat-1.0.18.dist-info/RECORD,,