monkeyfs 0.2.4__tar.gz → 0.2.5__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.
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/PKG-INFO +1 -1
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs/virtual.py +30 -14
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs.egg-info/PKG-INFO +1 -1
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/pyproject.toml +1 -1
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_directory_ops.py +60 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/LICENSE +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/README.md +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs/__init__.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs/base.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs/conformance.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs/context.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs/isolated.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs/mount.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs/patching/__init__.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs/patching/core.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs/patching/fdtable.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs/patching/install.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs/patching/patches.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs/py.typed +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs/readonly.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs/virtualfile.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs.egg-info/SOURCES.txt +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs.egg-info/dependency_links.txt +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs.egg-info/requires.txt +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/monkeyfs.egg-info/top_level.txt +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/setup.cfg +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_bulk_operations.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_conformance.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_expanduser.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_fd_emulation.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_finalization_and_invalidate.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_isolated.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_lazy_binary_read.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_metadata.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_mount.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_open_optional.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_patching.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_patching_pathlib.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_patching_safe_paths.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_protocol.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_ranged_read.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_readonly.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_symlink_entries.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_vfs_optional.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_vfs_size_limit.py +0 -0
- {monkeyfs-0.2.4 → monkeyfs-0.2.5}/tests/test_virtual.py +0 -0
|
@@ -536,6 +536,18 @@ class VirtualFS:
|
|
|
536
536
|
"""
|
|
537
537
|
return dict(self._meta_all())
|
|
538
538
|
|
|
539
|
+
@staticmethod
|
|
540
|
+
def _absolute(normalized: str) -> str:
|
|
541
|
+
"""A normalized key as an absolute path, for handing back to a
|
|
542
|
+
method that resolves its argument.
|
|
543
|
+
|
|
544
|
+
``resolve_path`` returns the key form, which has no leading
|
|
545
|
+
slash; passed on as it is, the next method reads it as relative
|
|
546
|
+
to the working directory and names a different path whenever
|
|
547
|
+
that is not ``/``.
|
|
548
|
+
"""
|
|
549
|
+
return "/" + normalized.strip("/")
|
|
550
|
+
|
|
539
551
|
def _normalize_path(self, path: str) -> str:
|
|
540
552
|
"""Normalize file path for consistent internal keys.
|
|
541
553
|
|
|
@@ -1094,11 +1106,12 @@ class VirtualFS:
|
|
|
1094
1106
|
if parent and not self.isdir("/" + parent):
|
|
1095
1107
|
raise FileNotFoundError(f"No such file or directory: '{path}'")
|
|
1096
1108
|
|
|
1097
|
-
# Check if already exists
|
|
1098
|
-
|
|
1099
|
-
|
|
1109
|
+
# Check if already exists (on the absolute path: ``path`` is the
|
|
1110
|
+
# key form, and checked as it is it would resolve a second time)
|
|
1111
|
+
absolute = self._absolute(normalized)
|
|
1112
|
+
if self.isfile(absolute):
|
|
1100
1113
|
raise FileExistsError(errno.EEXIST, os.strerror(errno.EEXIST), absolute)
|
|
1101
|
-
if self.isdir(
|
|
1114
|
+
if self.isdir(absolute):
|
|
1102
1115
|
if exist_ok:
|
|
1103
1116
|
return
|
|
1104
1117
|
raise FileExistsError(errno.EEXIST, os.strerror(errno.EEXIST), absolute)
|
|
@@ -1130,8 +1143,8 @@ class VirtualFS:
|
|
|
1130
1143
|
"""
|
|
1131
1144
|
path = self.resolve_path(path)
|
|
1132
1145
|
|
|
1133
|
-
if not exist_ok and self.isdir(path):
|
|
1134
|
-
absolute =
|
|
1146
|
+
if not exist_ok and self.isdir(self._absolute(path)):
|
|
1147
|
+
absolute = self._absolute(path)
|
|
1135
1148
|
raise FileExistsError(errno.EEXIST, os.strerror(errno.EEXIST), absolute)
|
|
1136
1149
|
|
|
1137
1150
|
parts = path.strip("/").split("/")
|
|
@@ -1157,16 +1170,19 @@ class VirtualFS:
|
|
|
1157
1170
|
"""
|
|
1158
1171
|
path = self.resolve_path(path)
|
|
1159
1172
|
normalized = self._normalize_path(path)
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1173
|
+
# Checked on the absolute path: ``path`` is the key form, and the
|
|
1174
|
+
# checks resolve their argument again.
|
|
1175
|
+
absolute = self._absolute(normalized)
|
|
1176
|
+
|
|
1177
|
+
if not self.exists(absolute):
|
|
1178
|
+
raise FileNotFoundError(f"No such directory: {absolute}")
|
|
1179
|
+
if self.isfile(absolute):
|
|
1180
|
+
raise NotADirectoryError(f"Not a directory: {absolute}")
|
|
1181
|
+
if not self.isdir(absolute):
|
|
1182
|
+
raise FileNotFoundError(f"No such directory: {absolute}")
|
|
1167
1183
|
|
|
1168
1184
|
# Check if directory is empty
|
|
1169
|
-
children = self.list(
|
|
1185
|
+
children = self.list(absolute)
|
|
1170
1186
|
if children:
|
|
1171
1187
|
raise OSError(f"Directory not empty: {path}")
|
|
1172
1188
|
|
|
@@ -514,3 +514,63 @@ def test_isolatedfs_recursive_listing_names_are_basenames(tmp_path):
|
|
|
514
514
|
("sub", "/probe/sub"),
|
|
515
515
|
("two.txt", "/probe/sub/two.txt"),
|
|
516
516
|
]
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
# -- a working directory other than / (issue #30) -------------------------
|
|
520
|
+
#
|
|
521
|
+
# rmdir, mkdir and makedirs resolved a path, then handed the result (the
|
|
522
|
+
# key form, with no leading slash) to checks that resolved it again,
|
|
523
|
+
# relative to the working directory. From / the two resolutions agreed;
|
|
524
|
+
# from anywhere else they named different paths.
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
@pytest.fixture(params=["/", "/workspace", "/workspace/src"])
|
|
528
|
+
def cwd_fs(request):
|
|
529
|
+
fs = VirtualFS({})
|
|
530
|
+
fs.makedirs("/workspace/src/inner", exist_ok=True)
|
|
531
|
+
fs.write("/workspace/f.txt", b"data")
|
|
532
|
+
fs.chdir(request.param)
|
|
533
|
+
return fs
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
def test_rmdir_removes_an_empty_directory_from_any_cwd(cwd_fs):
|
|
537
|
+
cwd_fs.rmdir("/workspace/src/inner")
|
|
538
|
+
assert not cwd_fs.exists("/workspace/src/inner")
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
def test_rmdir_refuses_a_missing_directory_by_its_absolute_path(cwd_fs):
|
|
542
|
+
with pytest.raises(FileNotFoundError, match="/workspace/nope"):
|
|
543
|
+
cwd_fs.rmdir("/workspace/nope")
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
def test_rmdir_refuses_a_file_from_any_cwd(cwd_fs):
|
|
547
|
+
with pytest.raises(NotADirectoryError):
|
|
548
|
+
cwd_fs.rmdir("/workspace/f.txt")
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
def test_mkdir_refuses_an_existing_directory_from_any_cwd(cwd_fs):
|
|
552
|
+
with pytest.raises(FileExistsError):
|
|
553
|
+
cwd_fs.mkdir("/workspace/src")
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
def test_mkdir_refuses_an_existing_file_and_leaves_it_a_file(cwd_fs):
|
|
557
|
+
with pytest.raises(FileExistsError):
|
|
558
|
+
cwd_fs.mkdir("/workspace/f.txt")
|
|
559
|
+
assert cwd_fs.isfile("/workspace/f.txt")
|
|
560
|
+
assert not cwd_fs.isdir("/workspace/f.txt")
|
|
561
|
+
assert cwd_fs.read("/workspace/f.txt") == b"data"
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
def test_makedirs_without_exist_ok_refuses_an_existing_directory(cwd_fs):
|
|
565
|
+
with pytest.raises(FileExistsError):
|
|
566
|
+
cwd_fs.makedirs("/workspace/src", exist_ok=False)
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
def test_a_relative_rmdir_and_mkdir_resolve_against_the_cwd():
|
|
570
|
+
fs = VirtualFS({})
|
|
571
|
+
fs.makedirs("/workspace/src", exist_ok=True)
|
|
572
|
+
fs.chdir("/workspace")
|
|
573
|
+
fs.mkdir("new")
|
|
574
|
+
assert fs.isdir("/workspace/new")
|
|
575
|
+
fs.rmdir("src")
|
|
576
|
+
assert not fs.exists("/workspace/src")
|
|
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
|
|
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
|
|
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
|