/usr/lib/python2.7/dist-packages/versuchung/files.py is in python-versuchung 1.1-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 | # This file is part of versuchung.
#
# versuchung is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# versuchung is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# versuchung. If not, see <http://www.gnu.org/licenses/>.
from versuchung.types import InputParameter, OutputParameter, Type
from versuchung.tools import before
from cStringIO import StringIO
import shutil
import csv
import os, stat
import hashlib
class FilesystemObject(InputParameter, OutputParameter, Type):
def __init__(self, default_name=""):
InputParameter.__init__(self)
OutputParameter.__init__(self)
Type.__init__(self)
self.__object_name = default_name
self.__enclosing_directory = os.path.abspath(os.curdir)
self.__force_enclosing_directory = False
def inp_setup_cmdline_parser(self, parser):
self.inp_parser_add(parser, None, self.__object_name)
def inp_extract_cmdline_parser(self, opts, args):
self.__object_name = self.inp_parser_extract(opts, None)
def inp_metadata(self):
return {self.name: self.__object_name}
@property
def path(self):
""":return: string -- path to the file/directory"""
if not self.__force_enclosing_directory:
if self.parameter_type == "input":
if self.static_experiment == self.dynamic_experiment:
self.__enclosing_directory = os.path.abspath(os.curdir)
else:
self.__enclosing_directory = self.static_experiment.base_directory
elif self.parameter_type == "output":
assert self.static_experiment == self.dynamic_experiment
self.__enclosing_directory = self.dynamic_experiment.base_directory
else:
self.__enclosing_directory = os.path.abspath(os.curdir)
return os.path.join(self.__enclosing_directory, self.__object_name)
@property
def basename(self):
return os.path.basename(self.path)
@property
def dirname(self):
return os.path.basename(self.path)
def set_path(self, base_directory, object_name):
assert base_directory[0] == "/"
self.__force_enclosing_directory = True
self.__enclosing_directory = base_directory
self.__object_name = object_name
class File(FilesystemObject):
"""Can be used as: **input parameter** and **output parameter**
The File type represents the content of a single file. Its contents
can be read and written most easily with the :attr:`value` property.
Alternatively, the method :meth:`write` appends new content if the
parameter `append` is set to `True`.
NB: The content of the file is flushed only after the experiment
finishes. Use :meth:`flush` to force writing the buffered data to
disk before the experiment finishes.
"""
def __init__(self, default_filename=""):
FilesystemObject.__init__(self, default_filename)
self.__value = None
@property
def value(self):
"""This attribute can be read and written and represent the
content of the specified file"""
if not self.__value:
try:
with open(self.path) as fd:
self.__value = self.after_read(fd.read())
except IOError:
# File couldn't be read
self.__value = self.after_read("")
return self.__value
@value.setter
def value(self, value):
self.__value = value
def write(self, content, append = False):
"""Similar to the :attr:`value` property. If the parameter
`append` is `False`, then the property :attr:`value` is reset
(i.e., overwritten), otherwise the content is appendend"""
if append:
self.value += content
else:
self.value = content
def after_experiment_run(self, parameter_type):
FilesystemObject.after_experiment_run(self, parameter_type)
assert parameter_type in ["input", "output"]
if parameter_type == "output":
self.flush()
def flush(self):
"""Flush the cached content of the file to disk"""
if not self.__value:
return
with open(self.path, "w+") as fd:
v = self.before_write(self.value)
if v is None:
v = ""
fd.write(v)
def copy_contents(self, filename):
"""Read the given file and replace the current .value with the
files content.
Flushes automatically afterwards."""
with open(filename) as fd:
self.value = self.after_read(fd.read())
self.flush()
def make_executable(self):
"""makes a file exectuable (chmod +x $file)"""
st = os.stat(self.path)
os.chmod(self.path, st.st_mode | stat.S_IEXEC)
def after_read(self, value):
"""To provide filtering of file contents in subclasses, overrwrite this method.
It is gets the file content as a string and returns the value()"""
return value
def before_write(self, value):
"""To provide filtering of file contents in subclasses, overrwrite this method.
This method gets the value() and returns a string, when the file is written to disk"""
return value
class Executable(File):
"""Can be used as: **input parameter**
An executable is a :class:`versuchung.files.File` that only
references an executable. It checksums the executable and puts the
checksum into the metadata. The executable is never changed.
"""
def __init__(self, default_filename):
File.__init__(self, default_filename)
@property
def value(self):
raise NotImplemented
@value.setter
def value(self, value):
raise NotImplementedError
def write(self, content, append = False):
raise NotImplementedError
def after_experiment_run(self, parameter_type):
pass
def flush(self):
raise NotImplementedError
def copy_contents(self, filename):
raise NotImplementedError
def make_executable(self):
raise NotImplementedError
def inp_metadata(self):
return {self.name + "-md5": hashlib.md5(open(self.path).read()).hexdigest()}
def execute(self, cmdline, *args):
"""Does start the executable with meth:`versuchung.execute.shell` and
args, which is of type list, as arguments."""
from versuchung.execute import shell
shell(self.path + " " + cmdline, *args)
class Directory_op_with:
def __init__(self):
self.__olddir = []
def __enter__(self):
self.__olddir.append(os.path.abspath(os.curdir))
os.chdir(self.path)
return self.path
def __exit__(self, *excinfo):
path = self.__olddir[-1]
del self.__olddir[-1]
os.chdir(path)
class Directory(FilesystemObject, Directory_op_with):
"""Can be used as: **input parameter** and **output parameter**
Represents the contents of directory. It can also be used with the
**with**-keyword to change the current working directory temporarily to this
directory::
with directory as dir:
# Do something with adjusted current working directory
print os.curdir
"""
def __init__(self, default_filename=""):
FilesystemObject.__init__(self, default_filename)
Directory_op_with.__init__(self)
self.__value = None
self.__new_files = []
def ___ensure_dir_exists(self):
if not os.path.exists(self.path):
os.mkdir(self.path)
# Ensure dir exists DECORATOR
__ensure_dir_exists = before(___ensure_dir_exists)
@property
def value(self):
""":return: list -- directories and files in given directory"""
if not self.__value:
self.__value = os.listdir(self.path)
return self.__value
def __iter__(self):
for name in self.value:
p = os.path.join(self.path, name)
if os.path.isdir(p):
d = Directory(name)
d.set_path(self.path, p)
self.subobjects[name] = d
yield d
else:
f = File(name)
f.set_path(self.path, p)
self.subobjects[name] = f
yield f
def before_experiment_run(self, parameter_type):
FilesystemObject.before_experiment_run(self, parameter_type)
if parameter_type == "output":
self.___ensure_dir_exists()
@__ensure_dir_exists
def new_file(self, name):
"""Generate a new :class:`~versuchung.files.File` in the
directory. It will be flushed automatically if the experiment
is over."""
f = File(name)
f.set_path(self.path, name)
self.subobjects[name] = f
return f
@__ensure_dir_exists
def new_directory(self, name):
"""Generate a new :class:`~versuchung.files.Directory` in the
directory. The directory <name> must not be present before"""
f = Directory(name)
f.set_path(self.path, name)
os.mkdir(f.path)
self.subobjects[name] = f
return f
@__ensure_dir_exists
def mirror_directory(self, path, include_closure = None):
"""Copies the contents of the given directory to this
directory.
The include closure is a function, which checks for every
(absolute) path in the origin directory, if it is mirrored. If
it is None, all files are included."""
if not include_closure:
include_closure = lambda arg: True
if not os.path.exists(path) and os.path.isdir(path):
raise RuntimeError("Argument is no directory")
path = os.path.abspath(path)
for root, dirs, files in os.walk(path):
root = root[len(path)+1:]
for d in dirs:
src = os.path.join(path, root, d)
if not include_closure(src):
continue
dst = os.path.join(self.path, root, d)
if not os.path.isdir(dst):
os.mkdir(dst)
for f in files:
src = os.path.join(path, root, f)
if not include_closure(src):
continue
dst = os.path.join(self.path, root, f)
shutil.copyfile(src,dst)
self.__value = None
class CSV_File(File):
"""Can be used as: **input parameter** and **output parameter**
It is a normal :class:`~versuchung.files.File` but the content of the file is
interpreted as a csv file. It is parsed before the value is
exposed to the user. And formatted before the content is written
to disk.
Internally the :mod:`csv` is used, so all arguments to
``csv.reader`` and ``csv.writer`` can be given in *csv_args*."""
value = File.value
"""Other than a normal CSV_File the value of a CSV_File is a list
of lists, which represents the structure of the csv file. This
value can be manipulated by the user.
>>> CSV_File("csv_output").value
[["1", "2", "3"]]"""
def __init__(self, default_filename = "", **csv_args):
File.__init__(self, default_filename)
self.csv_args = csv_args
def after_read(self, value):
fd = StringIO(value)
reader = csv.reader(fd, self.csv_args)
return list(reader)
def before_write(self, value):
fd = StringIO()
writer = csv.writer(fd, self.csv_args)
writer.writerows(value)
return fd.getvalue()
def write(self):
raise NotImplemented
def append(self, row):
"""Append a row to the csv file
It is just a shorthand for
>>> csv_file.value.append([1,2,3])
:param row: row to append
:type row: list."""
if type(row) != list:
raise TypeError("list of values required")
self.value.append(row)
|