Skip to content

Commit 93ea917

Browse files
committed
Add dedicated MemoryFS.scandir implementation
1 parent f13b62b commit 93ea917

File tree

1 file changed

+47
-15
lines changed

1 file changed

+47
-15
lines changed

fs/memoryfs.py

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import contextlib
77
import io
8+
import itertools
89
import os
910
import time
1011
import typing
@@ -298,6 +299,21 @@ def remove_open_file(self, memory_file):
298299
# type: (_MemoryFile) -> None
299300
self._open_files.remove(memory_file)
300301

302+
def to_info(self, namespaces=None):
303+
# type: (Optional[Collection[Text]]) -> Info
304+
namespaces = namespaces or ()
305+
info = {"basic": {"name": self.name, "is_dir": self.is_dir}}
306+
if "details" in namespaces:
307+
info["details"] = {
308+
"_write": ["accessed", "modified"],
309+
"type": int(self.resource_type),
310+
"size": self.size,
311+
"accessed": self.accessed_time,
312+
"modified": self.modified_time,
313+
"created": self.created_time,
314+
}
315+
return Info(info)
316+
301317

302318
@six.python_2_unicode_compatible
303319
class MemoryFS(FS):
@@ -372,33 +388,24 @@ def close(self):
372388

373389
def getinfo(self, path, namespaces=None):
374390
# type: (Text, Optional[Collection[Text]]) -> Info
375-
namespaces = namespaces or ()
376391
_path = self.validatepath(path)
377392
dir_entry = self._get_dir_entry(_path)
378393
if dir_entry is None:
379394
raise errors.ResourceNotFound(path)
380-
info = {"basic": {"name": dir_entry.name, "is_dir": dir_entry.is_dir}}
381-
if "details" in namespaces:
382-
info["details"] = {
383-
"_write": ["accessed", "modified"],
384-
"type": int(dir_entry.resource_type),
385-
"size": dir_entry.size,
386-
"accessed": dir_entry.accessed_time,
387-
"modified": dir_entry.modified_time,
388-
"created": dir_entry.created_time,
389-
}
390-
return Info(info)
395+
return dir_entry.to_info(namespaces=namespaces)
391396

392397
def listdir(self, path):
393398
# type: (Text) -> List[Text]
394399
self.check()
395400
_path = self.validatepath(path)
396401
with self._lock:
402+
# locate and validate the entry corresponding to the given path
397403
dir_entry = self._get_dir_entry(_path)
398404
if dir_entry is None:
399405
raise errors.ResourceNotFound(path)
400406
if not dir_entry.is_dir:
401407
raise errors.DirectoryExpected(path)
408+
# return the filenames in the order they were created
402409
return dir_entry.list()
403410

404411
if typing.TYPE_CHECKING:
@@ -503,13 +510,13 @@ def remove(self, path):
503510

504511
def removedir(self, path):
505512
# type: (Text) -> None
506-
# make sure the directory is empty
507-
if not self.isempty(path):
508-
return DirectoryNotEmpty(path)
509513
# make sure we are not removing root
510514
_path = self.validatepath(path)
511515
if _path == "/":
512516
raise errors.RemoveRootError()
517+
# make sure the directory is empty
518+
if not self.isempty(path):
519+
raise errors.DirectoryNotEmpty(path)
513520
# we can now delegate to removetree since we confirmed that
514521
# * path exists (isempty)
515522
# * path is a folder (isempty)
@@ -538,6 +545,31 @@ def removetree(self, path):
538545

539546
parent_dir_entry.remove_entry(file_name)
540547

548+
def scandir(
549+
self,
550+
path, # type: Text
551+
namespaces=None, # type: Optional[Collection[Text]]
552+
page=None, # type: Optional[Tuple[int, int]]
553+
):
554+
# type: (...) -> Iterator[Info]
555+
self.check()
556+
_path = self.validatepath(path)
557+
with self._lock:
558+
# locate and validate the entry corresponding to the given path
559+
dir_entry = self._get_dir_entry(_path)
560+
if dir_entry is None:
561+
raise errors.ResourceNotFound(path)
562+
if not dir_entry.is_dir:
563+
raise errors.DirectoryExpected(path)
564+
# if paging was requested, slice the filenames
565+
filenames = dir_entry.list()
566+
if page is not None:
567+
start, end = page
568+
filenames = filenames[start:end]
569+
# yield info with the right namespaces
570+
for name in filenames:
571+
yield dir_entry.get_entry(name).to_info(namespaces=namespaces)
572+
541573
def setinfo(self, path, info):
542574
# type: (Text, RawInfo) -> None
543575
_path = self.validatepath(path)

0 commit comments

Comments
 (0)