pathlibutil 0.1.8__tar.gz → 0.1.9__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pathlibutil
3
- Version: 0.1.8
3
+ Version: 0.1.9
4
4
  Summary: inherits from pathlib.Path with methods for hashing, copying, deleting and more
5
5
  Home-page: https://d-chris.github.io
6
6
  License: MIT
@@ -52,6 +52,9 @@ Description-Content-Type: text/markdown
52
52
  - `TimeInt` objects for `atime`, `ctime`, `mtime` and `birthtime`
53
53
  - `ByteInt` object for `size`
54
54
  - `Path.relative_to()` to get relative path from a file or directory, `walk_up` to walk up the directory tree.
55
+ - `Path.with_suffix()` to change the multiple suffixes of a file
56
+ - `Path.cwd()` to get the current working directory or executable path when script is bundled, e.g. with `pyinstaller`
57
+ - `Path.resolve()` to resolve a unc path to a mapped windows drive.
55
58
 
56
59
  ## Installation
57
60
 
@@ -261,3 +264,40 @@ backup = archive.move("./backup/")
261
264
  print(f"archive created: {archive.name} and moved to: {backup.parent}")
262
265
  ```
263
266
 
267
+ ## Example 6
268
+
269
+ Access the current working directory with optional parameter `frozen` to determine
270
+ different directories when script is bundled to an executable,
271
+ e.g. with `pyinstaller`.
272
+ > `Path.cwd()`
273
+
274
+ ```cmd
275
+ >>> poetry run examples/example6.py -b
276
+ Building frozen: K:/pathlibutil/examples/example6.exe
277
+ Build succeeded: 0
278
+
279
+ >>> poetry run examples/example6.py
280
+ we are not frozen
281
+
282
+ bundle dir is K:/pathlibutil/examples
283
+ sys.argv[0] is K:/pathlibutil/examples/example6.py
284
+ sys.executable is K:/pathlibutil/.venv/Scripts/python.exe
285
+ os.getcwd is K:/pathlibutil
286
+
287
+ Path.cwd(frozen=True) is K:/pathlibutil
288
+ Path.cwd(frozen=False) is K:/pathlibutil
289
+ Path.cwd(frozen=_MEIPASS) is K:/pathlibutil
290
+
291
+ >>> examples/example6.exe
292
+ we are ever so frozen
293
+
294
+ bundle dir is C:/Users/CHRIST~1.DOE/AppData/Local/Temp/_MEI106042
295
+ sys.argv[0] is examples/example6.exe
296
+ sys.executable is K:/pathlibutil/examples/example6.exe
297
+ os.getcwd is K:/pathlibutil
298
+
299
+ Path.cwd(frozen=True) is K:/pathlibutil/examples
300
+ Path.cwd(frozen=False) is K:/pathlibutil
301
+ Path.cwd(frozen=_MEIPASS) is C:/Users/CHRIST~1.DOE/AppData/Local/Temp/_MEI106042
302
+ ```
303
+
@@ -28,6 +28,9 @@
28
28
  - `TimeInt` objects for `atime`, `ctime`, `mtime` and `birthtime`
29
29
  - `ByteInt` object for `size`
30
30
  - `Path.relative_to()` to get relative path from a file or directory, `walk_up` to walk up the directory tree.
31
+ - `Path.with_suffix()` to change the multiple suffixes of a file
32
+ - `Path.cwd()` to get the current working directory or executable path when script is bundled, e.g. with `pyinstaller`
33
+ - `Path.resolve()` to resolve a unc path to a mapped windows drive.
31
34
 
32
35
  ## Installation
33
36
 
@@ -236,3 +239,40 @@ backup = archive.move("./backup/")
236
239
 
237
240
  print(f"archive created: {archive.name} and moved to: {backup.parent}")
238
241
  ```
242
+
243
+ ## Example 6
244
+
245
+ Access the current working directory with optional parameter `frozen` to determine
246
+ different directories when script is bundled to an executable,
247
+ e.g. with `pyinstaller`.
248
+ > `Path.cwd()`
249
+
250
+ ```cmd
251
+ >>> poetry run examples/example6.py -b
252
+ Building frozen: K:/pathlibutil/examples/example6.exe
253
+ Build succeeded: 0
254
+
255
+ >>> poetry run examples/example6.py
256
+ we are not frozen
257
+
258
+ bundle dir is K:/pathlibutil/examples
259
+ sys.argv[0] is K:/pathlibutil/examples/example6.py
260
+ sys.executable is K:/pathlibutil/.venv/Scripts/python.exe
261
+ os.getcwd is K:/pathlibutil
262
+
263
+ Path.cwd(frozen=True) is K:/pathlibutil
264
+ Path.cwd(frozen=False) is K:/pathlibutil
265
+ Path.cwd(frozen=_MEIPASS) is K:/pathlibutil
266
+
267
+ >>> examples/example6.exe
268
+ we are ever so frozen
269
+
270
+ bundle dir is C:/Users/CHRIST~1.DOE/AppData/Local/Temp/_MEI106042
271
+ sys.argv[0] is examples/example6.exe
272
+ sys.executable is K:/pathlibutil/examples/example6.exe
273
+ os.getcwd is K:/pathlibutil
274
+
275
+ Path.cwd(frozen=True) is K:/pathlibutil/examples
276
+ Path.cwd(frozen=False) is K:/pathlibutil
277
+ Path.cwd(frozen=_MEIPASS) is C:/Users/CHRIST~1.DOE/AppData/Local/Temp/_MEI106042
278
+ ```
@@ -2,8 +2,11 @@ import errno
2
2
  import hashlib
3
3
  import itertools
4
4
  import os
5
+ import re
5
6
  import shutil
6
- from typing import Callable, Dict, Generator, List, Set, Union
7
+ import subprocess
8
+ import sys
9
+ from typing import Callable, Dict, Generator, List, Literal, Set, Union
7
10
 
8
11
  from pathlibutil.base import BasePath, _Path
9
12
  from pathlibutil.types import ByteInt, StatResult, _stat_result, byteint
@@ -475,6 +478,95 @@ class Path(BasePath):
475
478
 
476
479
  return relative
477
480
 
481
+ @classmethod
482
+ def cwd(cls, *, frozen: Literal[True, False, "_MEIPASS"] = False) -> _Path:
483
+ """
484
+ Return a `Path` object representing the current working directory.
485
+
486
+ The `frozen` parameter takes only effect when the script is bundled to a
487
+ executable, e.g. with `pyinstaller`.
488
+
489
+ - `False`: Returns the current working directory, this is the default.
490
+ - `True`: Returns the directory of the executable.
491
+ - `"_MEIPASS"`: Returns the directory of the bundled resources.
492
+ """
493
+ if getattr(sys, "frozen", False):
494
+ if frozen is True:
495
+ return cls(sys.executable).parent
496
+ elif isinstance(frozen, str):
497
+ return cls(getattr(sys, frozen))
498
+
499
+ return super().cwd()
500
+
501
+ @classmethod
502
+ def _net_use(cls) -> Dict[str, str]:
503
+ """
504
+ Return a dictionary of mapped network drives. Keys are UNC paths and values
505
+ are drive letters.
506
+ """
507
+
508
+ def run(cmd: str) -> str:
509
+ """execute `command` and return stdout with cp850 encoding."""
510
+ result = subprocess.run(
511
+ cmd,
512
+ capture_output=True,
513
+ shell=True,
514
+ encoding="cp850",
515
+ )
516
+
517
+ return result.stdout
518
+
519
+ try:
520
+ mapped_drives = re.finditer(
521
+ r"^OK\s+(?P<drive>[A-Z]):\s+(?P<unc>\S+)",
522
+ run("net use"),
523
+ re.IGNORECASE | re.MULTILINE,
524
+ )
525
+ return {
526
+ match.group("unc") + "\\": match.group("drive") + ":\\"
527
+ for match in mapped_drives
528
+ }
529
+ except Exception:
530
+ return {}
531
+
532
+ def _resolve_unc(self) -> _Path:
533
+ """
534
+ Resolve UNC paths to mapped network drives.
535
+ """
536
+ if not hasattr(self.__class__, "_netuse"):
537
+ self.__class__._netuse = self._net_use()
538
+
539
+ try:
540
+ drive = self._netuse[self.anchor]
541
+ return self.__class__(drive).joinpath(self.relative_to(self.anchor))
542
+ except KeyError:
543
+ return self
544
+
545
+ def resolve(self, strict: bool = False, unc: bool = True) -> _Path:
546
+ """
547
+ Make the path absolute, resolving all symlinks on the way and also normalizing
548
+ it.
549
+
550
+ If `strict` is `True`, a `FileNotFoundError` will be raised if the path does
551
+ not exist.
552
+
553
+ On Windows if `unc` is `False`, UNC paths will be resolved to mapped network
554
+ drives.
555
+
556
+ >>> Path("T:/file.txt").resolve()
557
+ Path("\\\\server\\temp\\file.txt")
558
+
559
+ >>> Path("//server/temp/file.txt").resolve(unc=False)
560
+ Path("T:\\file.txt")
561
+ """
562
+
563
+ p = super().resolve(strict)
564
+
565
+ if unc is True or os.name != "nt":
566
+ return p
567
+
568
+ return p._resolve_unc()
569
+
478
570
 
479
571
  class Register7zFormat(Path, archive="7z"):
480
572
  """
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "pathlibutil"
3
- version = "v0.1.8"
3
+ version = "v0.1.9"
4
4
  description = "inherits from pathlib.Path with methods for hashing, copying, deleting and more"
5
5
  authors = ["Christoph Dörrer <d-chris@web.de>"]
6
6
  readme = "README.md"
@@ -44,6 +44,7 @@ docformatter = "^1.7.5"
44
44
  jinja2-pdoc = "^0.2.0"
45
45
  pdoc = "^14.3.0"
46
46
  click = "^8.1.7"
47
+ pyinstaller = "^6.5.0"
47
48
 
48
49
  [[tool.poetry.source]]
49
50
  name = "PyPI"
File without changes