44 # advance mtime (see issue5418) |
45 # advance mtime (see issue5418) |
45 util.rename(util.mktempcopy(path), path) |
46 util.rename(util.mktempcopy(path), path) |
46 checkandavoid() |
47 checkandavoid() |
47 |
48 |
48 |
49 |
49 class abstractvfs: |
50 class abstractvfs(abc.ABC): |
50 """Abstract base class; cannot be instantiated""" |
51 """Abstract base class; cannot be instantiated""" |
51 |
52 |
52 # default directory separator for vfs |
53 # default directory separator for vfs |
53 # |
54 # |
54 # Other vfs code always use `/` and this works fine because python file API |
55 # Other vfs code always use `/` and this works fine because python file API |
55 # abstract the use of `/` and make it work transparently. For consistency |
56 # abstract the use of `/` and make it work transparently. For consistency |
56 # vfs will always use `/` when joining. This avoid some confusion in |
57 # vfs will always use `/` when joining. This avoid some confusion in |
57 # encoded vfs (see issue6546) |
58 # encoded vfs (see issue6546) |
58 _dir_sep = b'/' |
59 _dir_sep = b'/' |
59 |
60 |
60 def __init__(self, *args, **kwargs): |
|
61 '''Prevent instantiation; don't call this from subclasses.''' |
|
62 raise NotImplementedError('attempted instantiating ' + str(type(self))) |
|
63 |
|
64 # TODO: type return, which is util.posixfile wrapped by a proxy |
61 # TODO: type return, which is util.posixfile wrapped by a proxy |
|
62 @abc.abstractmethod |
65 def __call__(self, path: bytes, mode: bytes = b'rb', **kwargs): |
63 def __call__(self, path: bytes, mode: bytes = b'rb', **kwargs): |
66 raise NotImplementedError |
64 ... |
67 |
65 |
|
66 @abc.abstractmethod |
68 def _auditpath(self, path: bytes, mode: bytes): |
67 def _auditpath(self, path: bytes, mode: bytes): |
69 raise NotImplementedError |
68 ... |
70 |
69 |
|
70 @abc.abstractmethod |
71 def join(self, path: Optional[bytes], *insidef: bytes) -> bytes: |
71 def join(self, path: Optional[bytes], *insidef: bytes) -> bytes: |
72 raise NotImplementedError |
72 ... |
73 |
73 |
74 def tryread(self, path: bytes) -> bytes: |
74 def tryread(self, path: bytes) -> bytes: |
75 '''gracefully return an empty string for missing files''' |
75 '''gracefully return an empty string for missing files''' |
76 try: |
76 try: |
77 return self.read(path) |
77 return self.read(path) |
682 |
682 |
683 def join(self, path: Optional[bytes], *insidef: bytes) -> bytes: |
683 def join(self, path: Optional[bytes], *insidef: bytes) -> bytes: |
684 return self.vfs.join(path, *insidef) |
684 return self.vfs.join(path, *insidef) |
685 |
685 |
686 |
686 |
687 class closewrapbase: |
687 class closewrapbase(abc.ABC): |
688 """Base class of wrapper, which hooks closing |
688 """Base class of wrapper, which hooks closing |
689 |
689 |
690 Do not instantiate outside of the vfs layer. |
690 Do not instantiate outside of the vfs layer. |
691 """ |
691 """ |
692 |
692 |
704 |
704 |
705 def __enter__(self): |
705 def __enter__(self): |
706 self._origfh.__enter__() |
706 self._origfh.__enter__() |
707 return self |
707 return self |
708 |
708 |
|
709 @abc.abstractmethod |
709 def __exit__(self, exc_type, exc_value, exc_tb): |
710 def __exit__(self, exc_type, exc_value, exc_tb): |
710 raise NotImplementedError('attempted instantiating ' + str(type(self))) |
711 ... |
711 |
712 |
|
713 @abc.abstractmethod |
712 def close(self): |
714 def close(self): |
713 raise NotImplementedError('attempted instantiating ' + str(type(self))) |
715 ... |
714 |
716 |
715 |
717 |
716 class delayclosedfile(closewrapbase): |
718 class delayclosedfile(closewrapbase): |
717 """Proxy for a file object whose close is delayed. |
719 """Proxy for a file object whose close is delayed. |
718 |
720 |