Commits

trampgeek committed 87a2982

Added PycodeFile class to PycodeTester

Comments (0)

Files changed (1)

pypy/translator/sandbox/pycodeClasses.py

     def __init__(self):
         environ = {'__name__': 'PycodeTester',
                    '__doc__': None,
-                   'raw_input': self.raw_input
+                   'raw_input': self.raw_input,
+                   'open': self.open
                   }
         code.InteractiveConsole.__init__(self, environ)
         self.output = ''
         self.syntaxError = self.exception = False
         self.lineNum = 0
         self.inputLines = None
-            
+       
+        
+    def open(self, filename, mode = 'r'):
+        '''Open a file for reading or writing. See 'PycodeFile' class below'''
+        mode = mode.replace('b','')
+        return PycodeFile(filename, mode.lower())
+                
         
     def setInput(self, inputString):
         if inputString == None:
         return self.output
 
 
+'''The PycodeFile class implements a rudimentary flat-file system so that
+   questions can be set that ask students to read or write files.
+   The only open modes permitted are r, w and a, with an optional b
+   that is ignored (i.e., r+, w+, a+ are not allowed). 
+'''
+class PycodeFile:
+    file_sys = {}  # A map from file name to string contents of file
+    
+    def __init__(self, filename, mode):
+        self.filename = filename
+        self.mode = mode
+        self.closed = False
+        if mode not in ['r', 'w', 'a']:
+            raise ValueError("Bad call to 'open'. In Pycode, mode string must be one of 'r', 'w', or 'a'")
+        if mode == 'r' and filename not in PycodeFile.file_sys:
+            raise IOError('File {0} not found'.format(filename))
+        if mode == 'w' or (mode == 'a' and filename not in PycodeFile.file_sys):
+            PycodeFile.file_sys[filename] = ''
+        if mode != 'a':
+            self.file_pos = 0
+        else:
+            self.file_pos = len(PycodeFile.file_sys[filename])
+        
+    def read(self, n = -1):
+        self.check_open('r')
+        contents = PycodeFile.file_sys[self.filename]
+        if n >= 0:
+            end_pos = min(len(contents), self.file_pos + n)
+        else:
+            end_pos = len(contents)
+        result = contents[self.file_pos : end_pos]
+        self.file_pos = end_pos
+        return result
+      
+    def readline(self):
+        contents = PycodeFile.file_sys[self.filename]
+        if self.file_pos >= len(contents):
+            return ''
+        else:	
+            n = contents.find('\n', self.file_pos)
+            if n != -1: # If found a newline ...
+                n += 1   # Adjust count to include newline itself
+            return self.read(n - self.file_pos)
+       
+    def readlines(self):
+        result = []
+        line = self.readline()
+        while line != '':
+            result.append(line)
+            line = self.readline()
+        return result
+    
+    def seek(self, offset, whence = 0):
+        file_length = len(PycodeFile.file_sys[self.filename])
+        if whence == 0:
+            self.file_pos = offset
+        elif whence == 1:
+            self.file_pos += offset
+        elif whence == 2:
+            self.file_pos = file_length + offset
+        else:
+            raise ValueError("Undefined 'whence' value for seek")
+        self.file_pos = min(max(0, self.file_pos), file_length)
+            
+    def check_open(self, reqd_mode):
+        if self.closed:
+            raise ValueError('Attempt to read or write a closed file')
+        if reqd_mode == 'r' and self.mode != 'r':
+            raise IOError('Attempt to read from a file open for writing')
+        if reqd_mode != 'r' and self.mode == 'r':
+            raise IOError('Attempt to write to or truncate a file open for reading')
+          
+    def __iter__(self):
+        return self._iterator()  
+            
+    def _iterator(self):
+        line = self.readline()
+        while line:
+            yield line
+            line = self.readline()
+
+    def close(self):
+        self.closed = True
+        
+    def flush(self):
+        pass
+    
+    def write(self, s):
+        self.check_open('w')
+        contents = PycodeFile.file_sys[self.filename]
+        new_contents = contents[:self.file_pos] + s
+        PycodeFile.file_sys[self.filename] = new_contents
+        self.file_pos = len(new_contents)
+    
+    def writelines(self, lines):
+        for line in lines:
+            self.write(line)
+            
+    def tell(self):
+        return self.file_pos
+
+    def truncate(self, size = None):
+        self.check_open('w')
+        if size is None:
+            size = self.file_pos
+        contents = PycodeFile.file_sys[self.filename]
+        if size < len(contents):
+            PycodeFile.file_sys[self.filename] = contents[:size]
+   
 
 
 class PycodeTester (object):
             result += ' differ at pos' + str(i)
             break
     return result
+