python: feature to create python callbacks/functions, now you can call hofs like map and reduce
parent
ba564d1b78
commit
4029bf7a17
|
@ -1,5 +1,6 @@
|
|||
USING: alien alien.c-types alien.destructors alien.libraries
|
||||
alien.libraries.finder alien.syntax assocs kernel sequences system ;
|
||||
alien.libraries.finder alien.syntax assocs classes.struct kernel sequences
|
||||
system ;
|
||||
IN: python.ffi
|
||||
|
||||
! << "python" { "3.0" "3" "2.7" "2.6" } ! Python 3 has a different api, enable someday
|
||||
|
@ -14,6 +15,32 @@ LIBRARY: python
|
|||
|
||||
C-TYPE: PyObject
|
||||
|
||||
! Methods
|
||||
CONSTANT: METH_OLDARGS 0x0000
|
||||
CONSTANT: METH_VARARGS 0x0001
|
||||
CONSTANT: METH_KEYWORDS 0x0002
|
||||
CONSTANT: METH_NOARGS 0x0004
|
||||
CONSTANT: METH_O 0x0008
|
||||
CONSTANT: METH_CLASS 0x0010
|
||||
CONSTANT: METH_STATIC 0x0020
|
||||
CONSTANT: METH_COEXIST 0x0040
|
||||
|
||||
C-TYPE: PyCFunction
|
||||
|
||||
STRUCT: PyMethodDef
|
||||
{ ml_name void* }
|
||||
{ ml_meth PyCFunction* }
|
||||
{ ml_flags int }
|
||||
{ ml_doc c-string } ;
|
||||
|
||||
FUNCTION: PyObject* PyCFunction_NewEx ( PyMethodDef* ml,
|
||||
PyObject* self,
|
||||
PyObject* module ) ;
|
||||
|
||||
CALLBACK: PyObject* PyCallback ( PyObject* self,
|
||||
PyObject* args,
|
||||
PyObject* kw ) ;
|
||||
|
||||
! Top-level
|
||||
FUNCTION: c-string Py_GetVersion ( ) ;
|
||||
FUNCTION: void Py_Initialize ( ) ;
|
||||
|
@ -61,6 +88,8 @@ FUNCTION: int PyList_Size ( PyObject* l ) ;
|
|||
! Steals the reference
|
||||
FUNCTION: int PyList_SetItem ( PyObject* l, int pos, PyObject* o ) ;
|
||||
|
||||
! Sequences
|
||||
FUNCTION: int PySequence_Check ( PyObject* o ) ;
|
||||
|
||||
! Modules
|
||||
FUNCTION: c-string PyModule_GetName ( PyObject* module ) ;
|
||||
|
@ -108,6 +137,9 @@ FUNCTION: long PyLong_AsLong ( PyObject* o ) ;
|
|||
! Floats
|
||||
FUNCTION: PyObject* PyFloat_FromDouble ( double d ) ;
|
||||
|
||||
! Types
|
||||
FUNCTION: int PyType_Check ( PyObject* obj ) ;
|
||||
|
||||
! Reference counting
|
||||
FUNCTION: void Py_IncRef ( PyObject* o ) ;
|
||||
FUNCTION: void Py_DecRef ( PyObject* o ) ;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
USING: alien.c-types alien.data kernel python.errors python.ffi ;
|
||||
USING: alien.c-types alien.data classes.struct kernel python.errors
|
||||
python.ffi ;
|
||||
IN: python.objects
|
||||
|
||||
! Objects
|
||||
|
@ -58,3 +59,10 @@ IN: python.objects
|
|||
|
||||
: py-list-set-item ( obj pos val -- )
|
||||
unsteal-ref PyList_SetItem check-zero ;
|
||||
|
||||
! Functions
|
||||
: <py-cfunction> ( alien -- cfunction )
|
||||
f swap METH_VARARGS f PyMethodDef <struct-boa> f f
|
||||
! It's not clear from the docs whether &Py_DecRef is right for
|
||||
! PyCFunction_NewEx, but I'm betting on it.
|
||||
PyCFunction_NewEx check-new-ref ;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
USING: alien destructors help.markup help.syntax python python.throwing
|
||||
quotations ;
|
||||
IN: python
|
||||
USING: python python.throwing help.markup help.syntax ;
|
||||
|
||||
HELP: py-initialize
|
||||
{ $description "Initializes the python binding. This word must be called before any other words in the api can be used" } ;
|
||||
|
@ -19,6 +20,21 @@ HELP: >py
|
|||
}
|
||||
{ $see-also py> } ;
|
||||
|
||||
HELP: quot>py-callback
|
||||
{ $values { "quot" { $quotation ( args kw -- ret ) } } { "alien" alien } }
|
||||
{ $description "Creates a python-compatible alien callback from a quotation." }
|
||||
{ $examples
|
||||
"This is how you create a callback which returns the double of its first positional parameter:"
|
||||
{ $unchecked-example
|
||||
"USING: python ;"
|
||||
": double-fun ( -- alien ) [ drop first 2 * ] quot>py-callback ;"
|
||||
}
|
||||
} ;
|
||||
|
||||
HELP: with-quot>py-cfunction
|
||||
{ $values { "alien" alien } { "quot" quotation } }
|
||||
{ $description "Wrapper for " { $link with-callback } " to be used when passing functions as arguments to Python functions. It should be used in conjunction with " { $link quot>py-callback } " which creates the callbacks this word consumes." } ;
|
||||
|
||||
HELP: python-error
|
||||
{ $error-description "When Python throws an exception, it is translated to this Factor error. " { $slot "type" } " is the class name of the python exception object, " { $slot "message" } " its string and " { $slot "traceback" } " a sequence of traceback lines, if the error has one, or " { $link f } " otherwise." } ;
|
||||
|
||||
|
@ -26,7 +42,7 @@ ARTICLE: "python" "Python binding"
|
|||
"The " { $vocab-link "python" } " vocab and its subvocabs implements a simple binding for libpython, allowing factor code to call native python."
|
||||
$nl
|
||||
"Converting to and from Python:"
|
||||
{ $subsections >py py> }
|
||||
{ $subsections >py py> quot>py-callback }
|
||||
"Error handling:"
|
||||
{ $subsections python-error }
|
||||
"Initialization and finalization:"
|
||||
|
@ -35,4 +51,5 @@ $nl
|
|||
{ $subsections py-import }
|
||||
"The vocab " { $vocab-link "python.syntax" } " implements a higher level factorific interface on top of the lower-level constructs in this vocab. Prefer to use that vocab most of the time."
|
||||
{ $notes "Sometimes the embedded python interpreter can't find or finds the wrong load path to it's module library. To counteract that problem it is recommended that the " { $snippet "PYTHONHOME" } " environment variable is set before " { $link py-initialize } " is called. E.g:" }
|
||||
{ $code "\"C:/python27-64bit/\" \"PYTHONHOME\" set-os-env" } ;
|
||||
{ $code "\"C:/python27-64bit/\" \"PYTHONHOME\" set-os-env" }
|
||||
{ $warning "All code that calls Python words should always be wrapped in a " { $link with-destructors } " context. The reason is that the words add references to Pythons internal memory heap which are removed when the destructors trigger." } ;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
USING: alien.c-types alien.data arrays assocs command-line fry
|
||||
USING: alien alien.c-types alien.data arrays assocs command-line fry
|
||||
hashtables init io.encodings.utf8 kernel namespaces
|
||||
python.errors python.ffi python.objects sequences
|
||||
specialized-arrays strings vectors ;
|
||||
|
@ -100,5 +100,15 @@ ERROR: missing-type type ;
|
|||
dup "__class__" getattr "__name__" getattr PyString_AsString
|
||||
py-type-dispatch get ?at [ call( x -- x ) ] [ missing-type ] if ;
|
||||
|
||||
! Callbacks
|
||||
: quot>py-callback ( quot: ( args kw -- ret ) -- alien )
|
||||
'[
|
||||
[ nip ] dip
|
||||
[ [ py> ] [ { } ] if* ] bi@ @ >py
|
||||
] PyCallback ; inline
|
||||
|
||||
: with-quot>py-cfunction ( alien quot -- )
|
||||
'[ <py-cfunction> @ ] with-callback ; inline
|
||||
|
||||
[ py-initialize ] "py-initialize" add-startup-hook
|
||||
[ py-finalize ] "py-finalize" add-shutdown-hook
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
USING: accessors arrays assocs continuations destructors fry io.files.temp
|
||||
kernel math namespaces python python.ffi python.objects python.syntax
|
||||
sequences sets splitting tools.test unicode.categories ;
|
||||
USING: accessors arrays assocs continuations destructors destructors.private
|
||||
fry io.files.temp kernel math namespaces python python.ffi python.objects
|
||||
python.syntax sequences sets splitting tools.test unicode.categories ;
|
||||
IN: python.syntax.tests
|
||||
|
||||
: py-test ( result quot -- )
|
||||
|
@ -77,6 +77,12 @@ PY-FROM: sys => getrefcount ( obj -- n ) ;
|
|||
[ 0 py-tuple-get-item getrefcount py> ] tri -
|
||||
] py-test
|
||||
|
||||
{ t } [
|
||||
6 <py-tuple>
|
||||
[ getrefcount py> 1 - ]
|
||||
[ always-destructors get [ alien>> = ] with count ] bi =
|
||||
] py-test
|
||||
|
||||
PY-METHODS: file =>
|
||||
close ( self -- )
|
||||
fileno ( self -- n )
|
||||
|
@ -166,3 +172,41 @@ PY-FROM: wsgiref.simple_server => make_server ( iface port callback -- httpd ) ;
|
|||
[ [ 987 >py basename drop ] ignore-errors ] with-destructors
|
||||
] times
|
||||
] unit-test
|
||||
|
||||
|
||||
! Working with types
|
||||
PY-METHODS: obj =>
|
||||
__name__ ( self -- n ) ;
|
||||
|
||||
PY-QUALIFIED-FROM: types => UnicodeType ( -- ) ;
|
||||
|
||||
{ "unicode" } [
|
||||
types:$UnicodeType $__name__ py>
|
||||
] py-test
|
||||
|
||||
! Make callbacks
|
||||
|
||||
PY-QUALIFIED-FROM: __builtin__ =>
|
||||
None ( -- )
|
||||
map ( func seq -- seq' )
|
||||
reduce ( func seq -- seq' ) ;
|
||||
|
||||
{ V{ 1 2 3 } } [
|
||||
__builtin__:$None { 1 2 3 } >py __builtin__:map py>
|
||||
] py-test
|
||||
|
||||
: double-fun ( -- alien )
|
||||
[ drop first 2 * ] quot>py-callback ;
|
||||
|
||||
{ V{ 2 4 16 2 4 68 } } [
|
||||
double-fun [ { 1 2 8 1 2 34 } >py __builtin__:map py> ] with-quot>py-cfunction
|
||||
] py-test
|
||||
|
||||
: reduce-func ( -- alien )
|
||||
[ drop first2 + ] quot>py-callback ;
|
||||
|
||||
{ 48 } [
|
||||
reduce-func [
|
||||
{ 1 2 8 1 2 34 } >py __builtin__:reduce py>
|
||||
] with-quot>py-cfunction
|
||||
] py-test
|
||||
|
|
Loading…
Reference in New Issue