-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathbatchpath.py
More file actions
184 lines (142 loc) · 5.88 KB
/
batchpath.py
File metadata and controls
184 lines (142 loc) · 5.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
Developer utility to generate and verify pathnames
GeneratePaths() takes a list of paths and returns a list of paths meeting
specified criteria (including access, filename extension, minimum size).
VerifyPaths() takes a list of paths and returns a boolean according to
whether the paths meet the specified criteria.
"""
import os
from functools import partial
__module__ = 'batchpath'
__version__ = '0.2'
class GeneratePaths:
"""Process list of paths and return an iterable of verified paths."""
def __init__(self):
self.access = None
self.extensions = None
self.filetype = None
self.minsize = None
self.paths = None
self.recursion = False
def _generator_file(self):
"""Generator for `self.filetype` of 'file'"""
for path in self.paths:
if os.path.isfile(path):
if isvalid(path, self.access, self.extensions,
minsize=self.minsize):
yield os.path.abspath(path)
elif os.path.isdir(path):
for root, _, fnames in self._walker(path):
yield from self._generator_rebase(fnames, root)
def _generator_other(self):
"""Generator for `self.filetype` other than file"""
for path in self.paths:
for root, dnames, fnames in self._walker(path):
yield from self._generator_rebase(dnames, root)
yield from self._generator_rebase(fnames, root)
def _generator_rebase(self, names, root):
"""Component of _generator_other()"""
return (_fixpath(root, base) for base in names if
isvalid(_fixpath(root, base), self.access,
self.extensions, self.filetype, self.minsize))
def _walker(self, path):
"""Walk a directory tree (optionally recursively)"""
for root, dnames, fnames in _walk(self.recursion)(path):
yield (root, dnames, fnames)
def all(self, paths, access=None, recursion=False):
"""
Iterates over `paths` (which may consist of files and/or directories).
Removes duplicates and returns list of valid paths meeting access
criteria.
"""
self.__init__()
self.access = access
self.filetype = 'all'
self.paths = paths
self.recursion = recursion
return _sorter(self._generator_other())
def dirs(self, paths, access=None, recursion=False):
"""
Iterates over `paths`. Removes duplicates and returns list of valid
directories meeting access criteria.
"""
self.__init__()
self.access = access
self.filetype = 'dir'
self.paths = paths
self.recursion = recursion
return _sorter(self._generator_other())
# pylint: disable=R0913
def files(self, paths, access=None, extensions=None,
minsize=None, recursion=False):
"""
Iterates over `paths` (which may consist of files and/or directories).
Removes duplicates and returns list of valid files meeting access,
extension, and minimum size criteria.
"""
self.__init__()
self.access = access
self.filetype = 'file'
self.extensions = extensions
self.minsize = minsize
self.paths = paths
self.recursion = recursion
return _sorter(self._generator_file())
class VerifyPaths:
"""Verify list of paths"""
def __init__(self):
self.failures = []
def all(self, paths, access=None):
"""Verify list of paths"""
self.failures = [path for path in paths if not
isvalid(path, access, filetype='all')]
return not self.failures
def dirs(self, paths, access=None):
"""Verify list of directories"""
self.failures = [path for path in paths if not
isvalid(path, access, filetype='dir')]
return not self.failures
def files(self, paths, access=None, extensions=None, minsize=None):
"""Verify list of files"""
self.failures = [path for path in paths if not
isvalid(path, access, extensions, 'file', minsize)]
return not self.failures
def _fixpath(root, base):
"""Return absolute, normalized, joined paths"""
return os.path.abspath(os.path.normpath(os.path.join(root, base)))
def _sorter(generated):
"""Return a list of paths sorted by dirname & basename."""
pairs = [(os.path.dirname(f), os.path.basename(f))
for f in set(list(generated))]
pairs.sort()
return [os.path.join(pair[0], pair[1]) for pair in pairs]
def _walk(recursion):
"""Returns a recursive or non-recursive directory walker"""
try:
from scandir import walk as walk_function
except ImportError:
from os import walk as walk_function
if recursion:
walk = partial(walk_function)
else:
def walk(path): # pylint: disable=C0111
try:
yield next(walk_function(path))
except NameError:
yield walk_function(path)
return walk
def checkext(path, extensions):
"""Test whether file extension is contained in `extensions`."""
return os.path.splitext(path)[1][1:] in extensions
def isvalid(path, access=None, extensions=None, filetype=None, minsize=None):
"""Check whether file meets access, extension, size, and type criteria."""
return ((access is None or os.access(path, access)) and
(extensions is None or checkext(path, extensions)) and
(((filetype == 'all' and os.path.exists(path)) or
(filetype == 'dir' and os.path.isdir(path)) or
(filetype == 'file' and os.path.isfile(path))) or
filetype is None) and
(minsize is None or (not os.path.isfile(path) or
os.path.getsize(path) > minsize)))