2

I don't know if there is an easy way of doing this that doesn't rely on manually writing down what the saved outputs from a script are so open to any suggestions. I want a function that runs at the end of my script and that automatically generates a text file with a name like: "IO_track_scriptname_date_time" Which has a list of the files I loaded and the files I saved (location links). And then saves this txt file to the desired destination.

Thank you for your help

Edit: Or any alternative way of keeping a log of inputs and outputs.

Agustin
  • 1,458
  • 1
  • 13
  • 30
  • 3
    You could write a wrapper for an `open` function, which would store the `path` and `mode`. At the end you would just dump the saved data. If the script is self-contained I would go for `class` based wrapper instead of using globals. – Marek Schwarz Nov 04 '19 at 13:17
  • do you have access to the filenames? if yes, you could look into the [logging](https://docs.python.org/3/library/logging.html) module – randomfigure Nov 04 '19 at 13:26
  • Thank you, I will have a look at both of those options – Agustin Nov 04 '19 at 13:31
  • @MarekSchwarz can I check I understand your suggestion correctly. Have a function that opens files by passing the path and the mode / way I want to open the file which stores the path and mode, and presumably something similar for the saved files? Also, I've never used wrappers so if you have any resources you recommend I'd appreciate that. Thanks! – Agustin Nov 04 '19 at 13:38
  • @Agustin By wrapper I mean `function` or `class` which internally uses usual code (here it would be an `open` function) and on top of that does e.g. the logging or whatever. Try the solution by @James. – Marek Schwarz Nov 04 '19 at 14:41

1 Answers1

1

Here is a thin object wrapper around the open function that tracks all of the files that are opened.

class Open:
    _open = open
    def __init__(self):
        self.opened_files = []
        self.fp = None

    def __call__(self,
                 file,
                 mode='r',
                 buffering=-1,
                 encoding=None,
                 errors=None,
                 newline=None,
                 closefd=True,
                 opener=None):

        self.fp = self._open(file, mode, buffering, encoding, errors,
            newline, closefd, opener)
        self.opened_files.append((mode, file))
        return self.fp

    def __enter__(self, *args, **kwargs):
        return self.__call__(*args, **kwargs)

    def __exit__(self, *exc_details):
        return self.fp.close()

    def __getattr__(self, attr):
        return getattr(self.fp, attr)

    def export(self, filename):
        with open(filename, 'w') as fp:
            for m, fn in self.opened_files:
                fp.write(f'({m}): {fn}\n')

To actually use it, you will need to overwrite the built-in open function with an instantiation of this class. If you have one file that you are calling, you can pop this into the __main__ block. i.e.

...

if __name__=='__main__':
   # code defining Open class here
   ...
   open = Open()
   # other code in __main__ here

   open.export("IO_track_scriptname_date_time.txt")
James
  • 32,991
  • 4
  • 47
  • 70
  • I've never really used the built-in open function. Do functions like np.loadtxt() go through this built-in open? Most of the files I'm opening I'm using a more specific function for. – Agustin Nov 04 '19 at 13:49
  • Some do, some don't. Your money may vary with this, but it is a reasonable start. – James Nov 04 '19 at 13:56