fork download
  1. import functools
  2. import sys
  3.  
  4. def file_reader(func):
  5. @functools.wraps(func)
  6. def helper(file, *args, **kwargs):
  7. return File(file, func, *args, **kwargs)
  8. return helper
  9.  
  10.  
  11. class File(object):
  12.  
  13. def __init__(self, file, func, *args, **kwargs):
  14. self.close_file = kwargs.pop('close', True)
  15. # accept either filename or file-like object
  16. self.file = file if hasattr(file, 'read') else open(file)
  17.  
  18. try:
  19. # func is responsible for self.file if it doesn't return it
  20. self.file = func(self.file, *args, **kwargs)
  21. except: # clean up on any error
  22. self.__exit__(*sys.exc_info())
  23. raise
  24.  
  25. # context manager support
  26. def __enter__(self):
  27. return self
  28.  
  29. def __exit__(self, *args, **kwargs):
  30. if not self.close_file:
  31. return # do nothing
  32. # clean up
  33. exit = getattr(self.file, '__exit__', None)
  34. if exit is not None:
  35. return exit(*args, **kwargs)
  36. else:
  37. exit = getattr(self.file, 'close', None)
  38. if exit is not None:
  39. exit()
  40.  
  41. # iterator support
  42. def __iter__(self):
  43. return self
  44.  
  45. def __next__(self):
  46. return next(self.file)
  47.  
  48. next = __next__ # Python 2 support
  49.  
  50. # delegate everything else to file object
  51. def __getattr__(self, attr):
  52. return getattr(self.file, attr)
  53.  
  54.  
  55. @file_reader
  56. def f(file):
  57. print(repr(file.read(10)))
  58. return file
  59.  
  60. file = f('prog.py') # use as ordinary function
  61. print(repr(file.read(20)))
  62. file.seek(0)
  63. for line in file:
  64. print(repr(line))
  65. break
  66. file.close() # need to close explicitly
  67.  
  68. with f('prog.py') as file: # use as a context manager
  69. print(repr(file.read(20)))
Success #stdin #stdout 0.02s 5824KB
stdin
Standard input is empty
stdout
'import fun'
'ctools\nimport sys\n\nd'
'import functools\n'
'import fun'
'ctools\nimport sys\n\nd'