Coverage for /Users/davegaeddert/Development/dropseed/plain/plain/plain/internal/files/utils.py: 49%
51 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-10-16 22:03 -0500
« prev ^ index » next coverage.py v7.6.1, created at 2024-10-16 22:03 -0500
1import os
2import pathlib
4from plain.exceptions import SuspiciousFileOperation
7def validate_file_name(name, allow_relative_path=False):
8 # Remove potentially dangerous names
9 if os.path.basename(name) in {"", ".", ".."}:
10 raise SuspiciousFileOperation("Could not derive file name from '%s'" % name)
12 if allow_relative_path:
13 # Use PurePosixPath() because this branch is checked only in
14 # FileField.generate_filename() where all file paths are expected to be
15 # Unix style (with forward slashes).
16 path = pathlib.PurePosixPath(name)
17 if path.is_absolute() or ".." in path.parts:
18 raise SuspiciousFileOperation(
19 "Detected path traversal attempt in '%s'" % name
20 )
21 elif name != os.path.basename(name):
22 raise SuspiciousFileOperation("File name '%s' includes path elements" % name)
24 return name
27class FileProxyMixin:
28 """
29 A mixin class used to forward file methods to an underlying file
30 object. The internal file object has to be called "file"::
32 class FileProxy(FileProxyMixin):
33 def __init__(self, file):
34 self.file = file
35 """
37 encoding = property(lambda self: self.file.encoding)
38 fileno = property(lambda self: self.file.fileno)
39 flush = property(lambda self: self.file.flush)
40 isatty = property(lambda self: self.file.isatty)
41 newlines = property(lambda self: self.file.newlines)
42 read = property(lambda self: self.file.read)
43 readinto = property(lambda self: self.file.readinto)
44 readline = property(lambda self: self.file.readline)
45 readlines = property(lambda self: self.file.readlines)
46 seek = property(lambda self: self.file.seek)
47 tell = property(lambda self: self.file.tell)
48 truncate = property(lambda self: self.file.truncate)
49 write = property(lambda self: self.file.write)
50 writelines = property(lambda self: self.file.writelines)
52 @property
53 def closed(self):
54 return not self.file or self.file.closed
56 def readable(self):
57 if self.closed:
58 return False
59 if hasattr(self.file, "readable"):
60 return self.file.readable()
61 return True
63 def writable(self):
64 if self.closed:
65 return False
66 if hasattr(self.file, "writable"):
67 return self.file.writable()
68 return "w" in getattr(self.file, "mode", "")
70 def seekable(self):
71 if self.closed:
72 return False
73 if hasattr(self.file, "seekable"):
74 return self.file.seekable()
75 return True
77 def __iter__(self):
78 return iter(self.file)