io module finished
authorStefan Israelsson Tampe <stefan.itampe@gmail.com>
Wed, 11 Apr 2018 19:10:33 +0000 (21:10 +0200)
committerStefan Israelsson Tampe <stefan.itampe@gmail.com>
Wed, 11 Apr 2018 19:10:33 +0000 (21:10 +0200)
modules/language/python/compile.scm
modules/language/python/exceptions.scm
modules/language/python/module.scm
modules/language/python/module/io.scm [new file with mode: 0644]
modules/language/python/module/os.scm
modules/language/python/module/python.scm
modules/language/python/module/subprocess.py
modules/language/python/with.scm

index e5bc219856ce1c3fad465f8f42f2d38099c965f7..fe3533b43920e8ff52556a22da41e2fda8e435cc 100644 (file)
              ,(C 'clear-warning-data)
              (fluid-set! (@@ (system base message) %dont-warn-list) '())
              ,@(map (lambda (s) `(,(C 'var) ,s)) globs)
-             ,@(map (g globs exp) x))))))
+             ,@(map (g globs exp) x)
+             (,(C 'export-all)))))))
 
 (define-syntax-parameter break
   (lambda (x) #'(values)))
     ((_ #t) #t)
     ((_ #f) #f)
     ((_ x ) (bool x))))
+
+(define (export-all)
+  (define mod (current-module))
+  (if (module-defined? mod '__all__)
+      (for ((x : (module-ref mod '__all__))) ()
+           (module-export! mod (string->symbol (scm-str x))))))
+  
index 60b850e3da6a0787f9d469d3e2c8d944a6e70267..99e8b977c5493a0338e02b23f38bd22a0d0f056f 100644 (file)
@@ -7,28 +7,11 @@
                           SyntaxError SystemException
                           OSError ProcessLookupError PermissionError
                           None NotImplemented NotImplementedError
-                         RunTimeError AssertionError))
+                         RunTimeError AssertionError
+                          ModuleNotFoundError BlockingIOError))
 
 (define-syntax-rule (aif it p x y) (let ((it p)) (if it x y)))
 
-(define StopIteration       'StopIteration)
-(define GeneratorExit       'GeneratorExit)
-(define SystemException     'SystemException)
-(define RuntimeError        'RuntimeError)
-(define IndexError          'IndexError)
-(define ValueError          'ValueError)
-(define None                'None)
-(define KeyError            'KeyError)
-(define TypeError           'TypeError)
-(define AttributeError      'AttributeError)
-(define SyntaxError         'SyntaxError)
-(define OSError             'OSError)
-(define ProcessLookupError  'ProcessLookupError)
-(define PermissionError     'PermissionError)
-(define NotImplementedError 'NotImplementedError)
-(define RunTimeError        'RunTimeError)
-(define AssertionError      'AssertionError)
-
 (define-python-class Exception ()
   (define __init__
     (case-lambda
            (format #f "~a"
                    (ref self '__name__))))))
 
+(define-syntax-rule (define-er nm k)
+  (define-python-class nm (Exception)))
+
+(define StopIteration          'StopIteration)
+(define GeneratorExit          'GeneratorExit)
+(define-er SystemException     'SystemException)
+(define-er RuntimeError        'RuntimeError)
+(define-er IndexError          'IndexError)
+(define-er ValueError          'ValueError)
+(define None                   'None)
+(define-er KeyError            'KeyError)
+(define-er TypeError           'TypeError)
+(define-er AttributeError      'AttributeError)
+(define-er SyntaxError         'SyntaxError)
+(define-er OSError             'OSError)
+(define-er ProcessLookupError  'ProcessLookupError)
+(define-er PermissionError     'PermissionError)
+(define-er NotImplementedError 'NotImplementedError)
+(define-er RunTimeError        'RunTimeError)
+(define AssertionError         'AssertionError)
+(define-er ModuleNotFoundError 'ModuleNotFoundError)
+(define-er BlockingIOError     'BlockingIOError)
 
 (define NotImplemented (list 'NotImplemented))
 
index 2940a9a17acff8449e9afff10370a526126c4f26..53aa1c2941046f7a30eb201bf70c55e4c4ee3e32 100644 (file)
       (rawset self '_isprivate p)))
 
   (define _cont
-    (lambda (self id pre l nm)
+    (lambda (self id pre l nm skip-error?)
       (if id
          (aif it (rawref self id)
               ((ref it '__init__) pre l nm)
               (begin
                 (rawset self id (Module pre l nm))
-                (_make self pre nm)))
-         (_make self pre nm))))
+                (_make self pre nm skip-error?)))
+         (_make self pre nm skip-error?))))
 
   (define _contupdate
     (lambda (self id pre l nm)
       (match l
        ((name)
        (set self '_path (reverse (cons name pre)))           
-       (_cont self #f   (cons name pre) #f (cons name nm)))
+       (_cont self #f   (cons name pre) #f (cons name nm) #f))
        
        ((name . (and l (name2 . _)))
        (set self '_path (reverse (cons name pre)))
-       (_cont self name2 (cons name pre) l  (cons name nm)))))
+       (_cont self name2 (cons name pre) l  (cons name nm) #t))))
        
 
      ((self l nm)
-      (_cont self #f l #f nm))
+      (_cont self #f l #f nm #f))
 
      ((self l)
       (if (pair? l)
                           (string-split l #\.)))))))
   
   (define _make
-    (lambda (self l nm)
+    (lambda (self l nm skip-error?)
       (rawset self '_private #f)
       (if (not (rawref self '_module))
          (begin
            (set self '__dict__ self)
            (set self '__name__ (string-join
                                 (map symbol->string (reverse nm)) "."))
-           (let ((_module (in-scheme (resolve-module (reverse l)))))
+           (let* ((_module (in-scheme (resolve-module (reverse l))))
+                   (public-i (and _module (module-public-interface _module))))
+              (if (and (not skip-error?) (not public-i))
+                  (raise (ModuleNotFoundError
+                          (format #f "No module named ~a"
+                                  (ref self '__name__)))))
+              
              (set self '_export (module-public-interface _module))
              (set self '_module _module)
              (hash-set! _modules l self))))))
diff --git a/modules/language/python/module/io.scm b/modules/language/python/module/io.scm
new file mode 100644 (file)
index 0000000..b2f9342
--- /dev/null
@@ -0,0 +1,481 @@
+(define-module (language python module io)
+  #:use-module (language python module exceptions)
+  #:use-module ((language python module os)
+                #:select (get_blocking))  
+  #:re-export (BlockingIOError)
+  #:export (UnsupportedOperation scm-port open DEFAULT_BUFFER_SIZE
+                                 IOBase RawIOBase BufferedIOBase FileIO
+                                 BytesIO BufferedReader BufferedWriter
+                                 BufferedRandom TextIOBase TextIOWrapper
+                                 StringIO))
+
+                                 
+
+(define (scm-port x)
+  (if (port? x)
+      x
+      (aif it (ref x '_port)
+           it
+           (raise ValueError "no port in scm-port"))))
+
+(define-python-class UnsupportedOperation (OSError ValueError))
+
+(define DEFAULT_BUFFER_SIZE 4096)
+
+(define (path-it path)
+  (aif it (ref path '__fspath__)
+       (it)
+       path))
+
+(def (open- path
+           (= mode      "r")
+           (= buffering -1 )
+           (= encoding   None)
+           (= errors     None)
+           (= newline    None)
+           (= closefd    #t)
+           (= opener     None))
+     
+     (define modelist (string->list mode))
+     (define path     (path-it path))
+     (define (clean ch l)
+       (filter (lambda (c) (not (eq? ch c))) l))
+     (let ((port (if (number? path)
+                     (begin
+                       (if (member #\a modelist)
+                           (seek path 0 SEEK_END))
+                       (if (member #\x modelist)
+                           (error "cannot use mode 'x' for fd input"))
+                       (cond
+                        ((member #\r modelist)
+                         (fdes->inport path))
+                        ((member #\w modelist)
+                         (fdes->outport path))))
+                     (begin
+                       (if (member #\x modelist)
+                           (if (file-exists? path)
+                               (raise OSError "mode='x' and file exists")
+                               (set mode (list->string
+                                          (clean #\x modelist)))))
+                       ((@ (guile) open-file) (path-it path) mode))))
+           
+           (errors   (if (bool errors)
+                         (scm-str errors)
+                         (let ((s (port-conversion-strategy port)))
+                           (cond
+                            ((eq? s 'error)      "strict")
+                            ((eq? s 'substitute) "replace")
+                            ((eq? s 'escape)     "basckslashreplace")))))
+           
+           (encoding (if (eq? encoding None)
+                         (port-encoding port)
+                         encoding)))
+       
+       
+       ;; encoding
+       (set self 'encoding encoding)
+       (set-port-encoding! port encoding)
+
+       (case buffering
+         ((-1)
+          (setvbuf port 'block DEFAULT_BUFFER_SIZE))
+         ((0)
+          (setvbuf port 'none))
+         ((1)
+          (setvbuf port 'line))
+         (else
+          (setvbuf port 'block buffering)))
+
+       (cond
+        ((equal? errors "strict")
+         (set-port-conversion-strategy! port 'error))
+        ((equal? errors "replace")
+         (set-port-conversion-strategy! port 'substitute))
+        ((equal? errors "basckslashreplace")
+         (set-port-conversion-strategy! port 'escape))
+        (else
+         (set-port-conversion-strategy! port 'escape)))
+
+       port))
+
+
+(def (open path
+           (= mode      "r")
+           (= buffering -1 )
+           (= encoding   None)
+           (= errors     None)
+           (= newline    None)
+           (= closefd    #t)
+           (= opener     None))
+
+     (let ((F
+            (FileIO (cons
+                     (open path mode buffering encoding errors
+                           newline closefd opener)
+                     path)
+                    mode)))
+       (if (member #\b (string->list mode))
+           F
+           (TextIOWrapper F encoding errors))))
+                   
+
+;;ABC
+
+(define-syntax-rule (check self . l)
+  (aif it (ref self 'raw)
+       (let ((self it))
+         (if (ref self 'closed)
+             (raise ValueError "IO operation on closed port"))
+         . l)
+       (begin
+         (if (ref self 'closed)
+             (raise ValueError "IO operation on closed port"))
+         . l)))
+
+(define-python-class IOBase ()
+  (define __init__
+    (lambda (self port)
+      (set self '_port  port)
+      (set self 'closed (port-closed? port))))
+
+  (define __getport__
+    (lambda (self)
+      (check self
+        (ref self _port))))
+  
+  (define close
+    (lambda (self)      
+      (check self
+         (close-port (ref self '_port))
+         (set self 'closed #t))))
+  
+  (define __enter__
+    (lambda (self)
+      (check self)
+      self))
+
+  (define __exit__
+    (lambda (self . x)
+      (check self
+         ((ref self 'close)))))
+
+  (define flush
+    (lambda (self)
+      (check self
+        (if ((ref self readable))  (drain-input  (ref self '_port)))
+        (if ((ref self writeable)) (force-output (ref self '_port))))))
+
+  (define isatty
+    (lambda (self)
+      (check self
+        (isatty? (ref self '_port)))))
+
+  (define __iter__
+    (lambda (self)
+      (check self)
+      self))
+
+  (define __next__
+    (lambda (self)
+      (check self
+          (raise StopIteration))))
+
+  (define readable
+    (lambda (self)
+      (check self
+         (output-port? (ref self '_port)))))
+
+  (define readline
+    (lam (self (= size -1))
+         (check self
+           (raise UnsupportedOperation))))
+
+  (define readlines
+    (lam (self (= hint -1))
+         (check self
+            (raise UnsupportedOperation))))
+
+  (define seekable
+    (lambda (self)
+      (check self
+        (catch #t
+          (lambda  () (seek (ref self '_port) 0 SEEK_CUR) #t)
+          (lambda  x  #f)))))
+                          
+  (define seek
+    (lambda* (self offset #:optional (whence SEEK_SET))
+      (check self
+        (if (not ((ref self seekable)))
+            (raise (ValueError "Not seekable")))
+        (seek (ref self '_port) offset whence))))
+
+
+  (define tell
+    (lambda (self)
+      (check self
+        (ftell (ref self '_port)))))
+
+  (define truncate
+    (lam (self (size None))
+         (check self
+           (if (eq? size None)
+               (truncate-file (ref self '_port))
+               (truncate-file (ref self '_port) size)))))
+
+             
+  (define writable
+    (lambda (self)
+      (check self
+         (input-port? (ref self '_port)))))
+
+  (define writelines
+    (lambda (self lines)
+      (check self
+        (raise UnsupportedOperation))))
+
+  (define __del__
+    (lambda (self
+       ((ref self 'close))))))
+
+
+
+      
+
+  
+(define-python-class RawIOBase (IOBase)
+  (define read
+    (lambda (self #:optional (size -1))
+      (check self
+      (bytes
+       (if (< size 0)
+           ((ref self 'readall))
+           (get-bytevector-n (ref self '_port) size))))))
+        
+
+  (define readall
+    (lambda (self)
+      (check self
+        (bytes
+         (get-bytevector-all (ref self '_port))))))
+
+  (define readinto
+    (lambda (self b)
+      (check self
+        (let* ((n (len b))
+               (b (scm-bytevector b))
+               (m (get-bytevector-n! (ref self '_port) b 0 n)))
+          (if (eof? m)
+              (if (get_blocking port)
+                  0
+                  None))))))
+  
+  (define write
+    (lambda (self b)
+      (check self
+        (let ((n (len b))
+              (b (scm-bytevector b)))
+          (put-bytevector (ref self '_port) b 0 n)
+          n)))))
+
+            
+(define-python-class BufferedIOBase (RawIOBase)
+  (define detach
+    (lambda (self)
+      (check self
+        (raise UnsupportedOperation "detach"))))
+
+  (define read1
+    (lambda* (self #:optional (size -1))
+      (check self
+        ((ref self 'read) size))))
+
+  (define readinto1
+    (lambda (self b)
+      (check self 
+        ((ref self 'readinto) b)))))
+
+(define-python-class FileIO (RawIOBase)
+  (define __init__
+    (lam (self name (= mode 'r') (= closefd #t) (= opener None))
+         (if (pair? name)
+             (set self '_port (car name))
+             (set self '_port
+                  (open_ it
+                         #:mode      mode
+                         #:closefd   closefd
+                         #:opener    opener)))
+         (set self 'mode mode)
+         (set self 'name (cdr name)))))
+
+
+(define-python-class BytesIO (BufferedIOBase)
+  (define __init__
+    (lambda* (self #:optional (initial_bytes None))
+      (if (eq? initial_bytes None)
+          (call-with-values open-bytevector-output-port
+            (lambda (port get-bytevector)
+              (set self '_port port)
+              (set self '_gtbv get-bytevector)))
+          (set self '_port
+               (open-bytevector-input-port initial_bytes)))))
+
+  (define getvalue
+    (lambda (self)
+      (check self
+             (bytes ((ref self '_gtbv)))))))
+
+(define-python-class BufferedReader (BufferedIOBase)
+  (define __init__
+    (lambda* (self raw #:optional (buffer_size DEFAULT_BUFFER_SIZE))
+      (let ((port (ref raw '_port)))
+        (case buffer_size
+          ((0)
+           (setvbuf port 'none))
+          ((1)
+           (setvbuf port 'line))
+          (else
+           (setvbuf port 'block buffer_size))))
+      (set self 'raw raw)))
+
+  (define peek
+    (lambda (self)
+      (raise UnsupportedOperation peek))))
+
+(define-python-class BufferedWriter (BufferedIOBase)
+  (define __init__
+    (lambda* (self raw #:optional (buffer_size DEFAULT_BUFFER_SIZE))
+      (let ((port (ref raw '_port)))
+        (case buffer_size
+          ((0)
+           (setvbuf port 'none))
+          ((1)
+           (setvbuf port 'line))
+          (else
+           (setvbuf port 'block buffer_size))))
+      (set self 'raw raw))))
+
+(define-python-class BufferedRandom (BufferedIOBase)
+  (define __init__
+    (lambda* (self raw #:optional (buffer_size DEFAULT_BUFFER_SIZE))
+      (let ((port (ref raw '_port)))
+        (case buffer_size
+          ((0)
+           (setvbuf port 'none))
+          ((1)
+           (setvbuf port 'line))
+          (else
+           (setvbuf port 'block buffer_size))))
+      (set self 'raw raw)))
+  
+  (define peek
+    (lambda (self)
+      (raise UnsupportedOperation peek))))
+
+(use-modules (ice-9 textual-ports))
+(use-modules (ice-9 rdelim))
+
+(define-python-class TextIOBase (IOBase)
+  (define read
+    (lambda (self size)
+      (check self
+        (let ((port (ref self '_port)))
+          (get-string-n port size)))))
+
+  (define readline
+    (lam (self (= size -1))
+         (check self
+           (let ((port (ref self '_port)))
+             (read-line port 'concat)))))
+
+  (define write
+    (lambda (self s)
+      (check self
+        (let ((port (ref self '_port)))
+          (put-string port (scm-str s) 0 (len s))
+          (len s))))))
+
+(define (get-port x)
+  (aif it (ref x '_port)
+       it
+       (aif it (ref x 'raw)
+            (get-port it)
+            (raise (ValueError "No port associated to IO wrapper")))))
+
+(define-python-class TextIOWrapper (TextIOBase)
+  (define __init__
+    (lam (self buffer
+               (= encoding       None)
+               (= errors         None)
+               (= newline        None)
+               (= line_buffering #f)
+               (= write_through  #f))
+         (set self 'raw buffer)
+         (let* ((port     (get-port buffer))
+                (errors   (if (bool errors)
+                              (scm-str errors)
+                              (let ((s (port-conversion-strategy port)))
+                                (cond
+                                 ((eq? s 'error)      "strict")
+                                 ((eq? s 'substitute) "replace")
+                                 ((eq? s 'escape)     "basckslashreplace")))))
+                (encoding (if (eq? encoding None)
+                              (port-encoding port)
+                              encoding)))
+           ;; encoding
+           (set self 'encoding encoding)
+           (set-port-encoding! port encoding)
+
+           ;; buffering
+           (if line_buffering
+               (setvbuf port 'line))
+           
+           (set self 'line_buffering line_buffering)
+           
+           ;; errors
+           (set self 'error errors)        
+           (cond
+            ((equal? errors "strict")
+             (set-port-conversion-strategy! port 'error))
+            ((equal? errors "replace")
+             (set-port-conversion-strategy! port 'substitute))
+            ((equal? errors "basckslashreplace")
+             (set-port-conversion-strategy! port 'escape))
+            (else
+             (set-port-conversion-strategy! port 'escape)))
+
+           ;; write trough
+           (set self 'write_trough write_trough)))))
+
+(define-python-class StringIO (TextIOBase)
+  (define __init__
+    (lam (self (= initial_value "") (= newline "\n"))
+         (set self 'newline newline)
+         (if (equal? initial_value "")
+             (set self '_port (open-output-str))
+             (set self '_port (open-input-str initial_value)))))
+
+  (define getvalue
+    (lambda (self)
+      (check self
+        (get-output-string (ref self port))))))
+
+
+
+
+         
+         
+
+
+
+
+
+        
+
+
+      
+
+
+  
+(define-python-class TextIOWrapper (TextIOBase))
+(define-python-class StringIO (TextIOBase))
+
index 863287dbfb8901560b3b028da9047a99c25139d4..757d5497837da960e4c4c7be9f7d66ae9bd96abc 100644 (file)
         (rm (fcntl3 fd F_GETFL (logand o (lognot O_NONBLOCK)))))))
 
 (define (get_blocking fd)
-  (if (= (logand O_NONBLOCK (rm (fcntl2 fd F_GETFL))) 0)
-      #f
-      #t))
+  (let ((fd (if (port? fd) (port->fdes fd) fd)))
+    (if (= (logand O_NONBLOCK (rm (fcntl2 fd F_GETFL))) 0)
+        #f
+        #t)))
 
 (define (readv fd buffers) (error "not implemented"))
 
index 30434afd20f52ad05002c66bb21832ae80ab0bc1..96b0aa73dfc8601a7951c0829542de1c2f6e67e1 100644 (file)
@@ -8,6 +8,7 @@
                     object-method))
   #:use-module (language python exceptions       )
   #:use-module ((language python module string   ) #:select ())
+  #:use-module ((language python module io       ) #:select (open))
   #:use-module (language python def              )
   #:use-module (language python for              )
   #:use-module (language python try              )
                              SyntaxError bool
                              len dir next dict None property range
                              tuple bytes bytearray eval locals globals
-                             compile exec type object
+                             compile exec type object open
                              )
   
   #:export (print repr complex float int str
                   set all any bin callable reversed
                   chr classmethod staticmethod objectmethod
-                  divmod enumerate filter open
+                  divmod enumerate filter
                   getattr hasattr setattr hex isinstance issubclass
                   iter map sum id input oct ord pow super
                   sorted zip
 
 (define-syntax-rule (aif it p x y) (let ((it p)) (if it x y)))
 
-(define (path-it path)
-  (aif it (ref path '__fspath__)
-       (it)
-       path))
-
 (define print
   (case-lambda
     (()  ((@ (guile) format) #t "~%"))
                   (yield (reverse r))
                   (lp))))))))))
 
-(define DEFAULT_BUFFER_SIZE 4096)
-(def (open path
-           (= mode      "r")
-           (= buffering -1 )
-           (= encoding   None)
-           (= errors     None)
-           (= newline    None)
-           (= closefd    #t)
-           (= opener     None))
-     
-     (define modelist (string->list mode))
-     (define path     (path-it path))
-     (define (clean ch l)
-       (filter (lambda (c) (not (eq? ch c))) l))
-     (let ((port (if (number? path)
-                     (begin
-                       (if (member #\a modelist)
-                           (seek path 0 SEEK_END))
-                       (if (member #\x modelist)
-                           (error "cannot use mode 'x' for fd input"))
-                       (cond
-                        ((member #\r modelist)
-                         (fdes->inport path))
-                        ((member #\w modelist)
-                         (fdes->outport path))))
-                     (begin
-                       (if (member #\x modelist)
-                           (if (file-exists? path)
-                               (raise OSError "mode='x' and file exists")
-                               (set mode (list->string
-                                          (clean #\x modelist)))))                                                            
-                       ((@ (guile) open-file) (path-it path) mode)))))
-
-       (case buffering
-         ((-1)
-          (setvbuf port 'block DEFAULT_BUFFER_SIZE))
-         ((0)
-          (setvbuf port 'none))
-         ((1)
-          (setvbuf port 'line))
-         (else
-          (setvbuf port 'block buffering)))
-
-       port))
-
-
 (define-python-class ClassMethod  ())
 (define-python-class StaticMethod ())
 (define-python-class Funcobj      ())
index 0d8ee7edcf3c5bcc0e1391848db627cfbc649d0b..d4dd259c11220a701f5da559346eaae8c7272523 100644 (file)
@@ -86,7 +86,6 @@ class CalledProcessError(SubprocessError):
         # .stdout is a transparent alias for .output
         self.output = value
 
-
 class TimeoutExpired(SubprocessError):
     """This exception is raised when the timeout expires while waiting for a
     child process.
@@ -133,12 +132,12 @@ else:
         import threading
     except ImportError:
         import dummy_threading as threading
-
+    pk(1)
     # When select or poll has indicated that the file is writable,
     # we can write up to _PIPE_BUF bytes without risk of blocking.
     # POSIX defines PIPE_BUF as >= 512.
     _PIPE_BUF = getattr(select, 'PIPE_BUF', 512)
-
+    pk(2)
     # poll/select have the advantage of not requiring any extra file
     # descriptor, contrarily to epoll/kqueue (also, they require a single
     # syscall).
index eab5c55a2522f459907070cf1e87658c24a762fb..0193189a2185137a9355ac81b5c5eadd093a145e 100644 (file)
@@ -25,7 +25,7 @@
                  (lambda ()
                    (let ((id (enter))) . code))
                  (#:except #t =>
-                   (lambda (tag l)                   
+                    (lambda (tag l)                  
                      (set! type  (if (pyclass? tag)
                                      tag
                                      (aif it (ref tag '__class__)