|
5 | 5 |
|
6 | 6 | import contextlib |
7 | 7 | import io |
| 8 | +import itertools |
8 | 9 | import os |
9 | 10 | import time |
10 | 11 | import typing |
@@ -298,6 +299,21 @@ def remove_open_file(self, memory_file): |
298 | 299 | # type: (_MemoryFile) -> None |
299 | 300 | self._open_files.remove(memory_file) |
300 | 301 |
|
| 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 | + |
301 | 317 |
|
302 | 318 | @six.python_2_unicode_compatible |
303 | 319 | class MemoryFS(FS): |
@@ -372,33 +388,24 @@ def close(self): |
372 | 388 |
|
373 | 389 | def getinfo(self, path, namespaces=None): |
374 | 390 | # type: (Text, Optional[Collection[Text]]) -> Info |
375 | | - namespaces = namespaces or () |
376 | 391 | _path = self.validatepath(path) |
377 | 392 | dir_entry = self._get_dir_entry(_path) |
378 | 393 | if dir_entry is None: |
379 | 394 | 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) |
391 | 396 |
|
392 | 397 | def listdir(self, path): |
393 | 398 | # type: (Text) -> List[Text] |
394 | 399 | self.check() |
395 | 400 | _path = self.validatepath(path) |
396 | 401 | with self._lock: |
| 402 | + # locate and validate the entry corresponding to the given path |
397 | 403 | dir_entry = self._get_dir_entry(_path) |
398 | 404 | if dir_entry is None: |
399 | 405 | raise errors.ResourceNotFound(path) |
400 | 406 | if not dir_entry.is_dir: |
401 | 407 | raise errors.DirectoryExpected(path) |
| 408 | + # return the filenames in the order they were created |
402 | 409 | return dir_entry.list() |
403 | 410 |
|
404 | 411 | if typing.TYPE_CHECKING: |
@@ -503,13 +510,13 @@ def remove(self, path): |
503 | 510 |
|
504 | 511 | def removedir(self, path): |
505 | 512 | # type: (Text) -> None |
506 | | - # make sure the directory is empty |
507 | | - if not self.isempty(path): |
508 | | - return DirectoryNotEmpty(path) |
509 | 513 | # make sure we are not removing root |
510 | 514 | _path = self.validatepath(path) |
511 | 515 | if _path == "/": |
512 | 516 | raise errors.RemoveRootError() |
| 517 | + # make sure the directory is empty |
| 518 | + if not self.isempty(path): |
| 519 | + raise errors.DirectoryNotEmpty(path) |
513 | 520 | # we can now delegate to removetree since we confirmed that |
514 | 521 | # * path exists (isempty) |
515 | 522 | # * path is a folder (isempty) |
@@ -538,6 +545,31 @@ def removetree(self, path): |
538 | 545 |
|
539 | 546 | parent_dir_entry.remove_entry(file_name) |
540 | 547 |
|
| 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 | + |
541 | 573 | def setinfo(self, path, info): |
542 | 574 | # type: (Text, RawInfo) -> None |
543 | 575 | _path = self.validatepath(path) |
|
0 commit comments