PythonMonkey es un motor JavaScript Mozilla Spidermonkey integrado en el tiempo de ejecución de Python, utilizando el motor Python para proporcionar el entorno de host JavaScript.
Presentamos métodos de matriz y objeto de JavaScript implementados en la lista de Python y los diccionarios utilizando la API CPython C, y el inverso utilizando la API C ++ JavaScript C ++ de Mozilla Firefox Spidermonkey.
Este proyecto ha llegado a MVP a partir de septiembre de 2024. Está en mantenimiento por distribución.
Las contribuciones y comentarios externas son bienvenidos y alentados.
$ pip install pythonmonkey from pythonmonkey import eval as js_eval
js_eval ( "console.log" )( 'hello, world' )eval() en Python que acepta el código JS y devuelve los valores JS-> Python coaccionadosrequire función, devuelve un DICT coercial de exportaciones de módulosLea esto si desea construir una versión local.
Necesitará lo siguiente instalado (que se puede hacer automáticamente ejecutando ./setup.sh ):
Ejecute poetry install . Este comando compila automáticamente el proyecto e instala el proyecto, así como las dependencias en la poesía VirtualEnv. Si desea construir los documentos, configure la variable de entorno BUILD_DOCS , como así: BUILD_DOCS=1 poetry install . PythonMonkey admite múltiples tipos de compilación, que puede construir estableciendo la variable de entorno BUILD_TYPE , como así: BUILD_TYPE=Debug poetry install . Los tipos de compilación son (insensibles a los casos):
Release : símbolos pelados, optimizaciones máximas (predeterminadas)DRelease : igual que Release , excepto que los símbolos no se despojanDebug : optimizaciones mínimasSanitize : igual que Debug , excepto con DirectSanitizer habilitadoProfile : igual que Debug , excepto que el perfil está habilitadoNone : no compile (útil si solo desea construir los documentos) Si está utilizando VScode, puede presionar CTRL + Shift + B para ejecutar la tarea de compilación: tenemos el archivo tasks.json configurado para usted.
poetry install --no-root --only=devpoetry run pytest ./tests/pythonpoetry run bash ./peter-jr ./tests/js/Para los usuarios de VSCode, similar a la tarea de compilación, tenemos una tarea de prueba lista para usar.
Se requiere NPM (Node.js) durante la instalación solo para llenar las dependencias JS.
$ pip install pythonmonkey$ pip install --extra-index-url https://nightly.pythonmonkey.io/ --pre pythonmonkey pythonmonkey está disponible en la poesía VirtualEnv una vez que compiló el proyecto usando poesía.
$ poetry run python Python 3.10 .6 ( main , Nov 14 2022 , 16 : 10 : 14 ) [ GCC 11.3 .0 ] on linux
Type "help" , "copyright" , "credits" or "license" for more information .
> >> import pythonmonkey as pm
>> > hello = pm . eval ( "() => {return 'Hello from Spidermonkey!'}" )
>> > hello ()
'Hello from Spidermonkey!'Alternativamente, puede crear paquetes instalables ejecutando
$ cd python/pminit && poetry build --format=sdist && cd - && mv -v python/pminit/dist/ * ./dist/
$ poetry build --format=wheel e instálelos por pip install ./dist/* .
La instalación pythonmonkey también instalará el paquete pminit como dependencia. Sin embargo, pip uninstall un paquete no eliminará automáticamente sus dependencias.
Si desea eliminar limpiamente pythonmonkey de su sistema, haga lo siguiente:
$ pip uninstall pythonmonkey pminitpoetry run gdb python . Ver Python Wiki: DebuggingWithgdb Si está utilizando VScode, es más conveniente depurar en el depurador incorporado de VScode. Simplemente presione F5 en un archivo de Python abierto en el editor para comenzar a depurar; tenemos el archivo launch.json configurado para usted.
Estos métodos se exportan desde el módulo PythonMonkey. Ver definiciones en Python/Pythonmonkey/Pythonmonkey.pyi.
Evaluar el código JavaScript. La semántica de esta evaluación es muy similar a la evaluación utilizada en JavaScript; La última expresión evaluada en la cadena code se usa como el valor de retorno de esta función. Para evaluar code en modo estricto, la primera expresión debe ser la cadena "use strict" .
La función EVALO admite un objeto Opciones que puede afectar la forma en que se evalúa el código JS de manera poderosa. Se basan en gran medida en CompileOptions de Spidermonkey. Las teclas de opción compatible son:
filename : establezca el nombre de archivo de este código a los efectos de generar trazas de pila, etc.lineno : Establezca el desplazamiento del número de línea de este código a los efectos de generar trazas de pila, etc.column : configure el número de la columna de este código a los efectos de generar trazas de pila, etc.mutedErrors : si se establece en True , se ignoran los errores de evaluación o los rechazos no controlados ("silenciados"). False predeterminado.noScriptRval : si False , devuelve el último valor de expresión del script como el valor de resultado al llamado. False predeterminado.selfHosting : experimentalstrict : evalúa por la fuerza en modo estricto ( "use strict" ). False predeterminado.module : indique que el archivo es un módulo ECMAScript (siempre un código de modo estricto y no permita los comentarios HTML). False predeterminado.fromPythonFrame : Genere el equivalente del nombre de archivo, el lino y la columna basada en la ubicación de la llamada de Python a Eval. Esto permite evaluar los literales de cadenas multilíneas de Python y generar trazas de pila en JS que apuntan al error en el archivo fuente de Python. undefined en JavaScript; Si desea devolver una función, debe evaluar una expresión: pythonmonkey . eval ( "myFunction() { return 123 }; myFunction" ) pythonmonkey . eval ( "(myFunction() { return 123 })" ) pythonmonkey . eval ( "(thing) => console.log('you said', thing)" )( "this string came from Python" ) Devolver las exportaciones de un módulo CommonJS identificado por moduleIdentifier , utilizando la semántica estándar de CommonJS
require.js - módulo JavaScript; El código fuente decora el objeto exports.py - módulo de pitón; El código fuente decora exports DICT.json - módulo JSON; Las exportaciones son el resultado de analizar el texto JSON en el archivoUn dict de pitón que es equivalente al global este objeto en JavaScript.
Función de fábrica que devuelve una nueva función de requisito
Cargue y evalúe un módulo del programa (principal). Los módulos del programa deben estar escritos en JavaScript. Los módulos del programa no son necesarios a menos que el punto de entrada principal de su programa esté escrito en JavaScript.
Se debe tener cuidado para garantizar que solo se ejecute un módulo de programa por contexto JS.
Examina el code de cadena y devuelve False si la cadena podría convertirse en una declaración JS válida con la adición de más líneas. Esto se usa internamente por PMJS y puede ser muy útil para construir reples de JavaScript; La idea es acumular líneas en un amortiguador hasta que ISCompilableUnit sea verdadera, luego evaluar todo el búfer.
Devuelve una función Python que invoca function con el nuevo operador JS.
import pythonmonkey as pm
> >> pm . eval ( "class MyClass { constructor() { console.log('ran ctor') }}" )
> >> MyClass = pm . eval ( "MyClass" )
> >> MyClass ()
Traceback ( most recent call last ):
File "<stdin>" , line 1 , in < module >
pythonmonkey . SpiderMonkeyError : TypeError : class constructors must be invoked with 'new'
>> > MyClassCtor = pm . new ( MyClass )
>> > MyClassCtor ()
ran ctor
{}
>> > Este es el operador JS typeof , envuelto en una función para que pueda usarse fácilmente desde Python.
Todas las clases estándar de JS (matriz, función, objeto, fecha ...) y objetos (global este, finalizationregistry ...) están disponibles como exportaciones del módulo PythonMonkey. Estas exportaciones se generan enumerando la variable global en el contexto actual de Spidermonkey. La lista actual es:
undefined, Boolean, JSON, Date, Math, Number, String, RegExp, Error, InternalError, AggregateError, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError, ArrayBuffer, Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64array, uint8ClampedArray, bigInt64array, biguint64Array, bigInt, proxy, débilmap, map, set, dataView, símbolo, intl, reflexionar, débil, promesa, webassembly, weakref, iterator, asynciterator, nan, infinity, isnan, isfinite, parsefloat, parseint, unypap, unyc, unsesc, Decodeuri Encodeuri, decodeuricomponent, codeneuricomponent, función, objeto, debuggerglobal, finalización del registro, matriz, globalthis
Ver definiciones en Python/Pythonmonkey/Global.D.TS. Incluido:
consoleatobbtoasetTimeoutclearTimeout El subsistema CommonJS se activa invocando las exportaciones require o createRequire del módulo (Python) Pythonmonkey.
requireexportsmodule__filename__dirnamepython.print - La función de impresión de Pythonpython.getenv - la función Python Getenvpython.stdout : un objeto con métodos read y write , que leen y escriben en stdoutpython.stderr : un objeto con métodos read y write , que leen y escriben en Stderrpython.exec - la función de ejecutivo de pythonpython.eval - la función de evaluación de Pythonpython.exit - Salir a través de sys.exit (); El código de salida es el argumento de función o python.exit.code .python.paths - The Python Sys.paths List, visible en JS como una matriz Al enviar variables de Python a JavaScript, PythonMonkey coaccionará o envolverá inteligentemente sus variables en función de su tipo. PythonMonkey compartirá tiendas de respaldo (use la misma memoria) para ctypes, matrices mecanografiadas y cadenas; Mover estos tipos a través de la barrera del idioma es extremadamente rápido porque no hay copia involucrada.
Nota: Hay planes en Python 3.12 (PEP 623) para cambiar la representación de cadena interna de modo que cada carácter de la cadena use cuatro bytes de memoria. Esto romperá las transferencias de cadena rápida para PythonMonkey, ya que se basa en que el diseño de la memoria sea el mismo en Python y JavaScript. Al momento de escribir este artículo (julio de 2023), las cuerdas de Python "clásicas" todavía funcionan en los 3.12 lanzamientos beta.
Donde la tienda de respaldo compartido no es posible, PythonMonkey emitirá automáticamente envoltorios que usan la estructura de datos "real" como su autoridad de valor. Solo se copian intrínsecos inmutables. Esto significa que si actualiza un objeto en JavaScript, el DICT correspondiente en Python se actualizará, etc.
Los métodos de matriz y objetos de JavaScript se implementan en la lista de Python y los diccionarios, y viceversa.
| Tipo de pitón | Tipo de JavaScript |
|---|---|
| Cadena | cadena |
| Entero | número |
| Bool | booleano |
| Función | función |
| Dictarse | objeto |
| Lista | Formación |
| de fecha y hora | Objeto de fecha |
| esperable | Promesa |
| Error | Objeto de error |
| Buffer | Arraybuffer |
| Tipo de JavaScript | Tipo de pitón |
|---|---|
| cadena | pythonmonkey.jsstringproxy (cadena) |
| número | Flotar |
| bigint | pythonmonkey.bigint (entero) |
| booleano | Bool |
| función | pythonmonkey.jsfunctionProxy |
| Objeto - la mayoría | pythonmonkey.jsobjectproxy (dict) |
| Objeto - Fecha | de fecha y hora |
| Objeto - Array | pythonmonkey.jsarrayproxy (lista) |
| Objeto - Promesa | esperable |
| Objeto - ArrayBuffer | Buffer |
| Objeto - Tipo de matrices | Buffer |
| Objeto - Error | Error |
Puede obligar a un número a JavaScript a ser coaccionado como entero lanzándolo a Bigint:
function myFunction ( a , b ) {
const result = calculate ( a , b ) ;
return BigInt ( Math . floor ( result ) ) ;
} El objeto pythonmonkey.bigint funciona como un int en Python, pero será coaccionado como un bigint en JavaScript:
import pythonmonkey
def fn myFunction ()
result = 5
return pythonmonkey . bigint ( result )Puede usar un JavaScript iife para crear un alcance en el que pueda inyectar símbolos de Python:
globalThis . python . exit = pm . eval ( """'use strict';
(exit) => function pythonExitWrapper(exitCode) {
if (typeof exitCode === 'number')
exitCode = BigInt(Math.floor(exitCode));
exit(exitCode);
}
""" )( sys . exit ); Necesita un bucle de eventos que se ejecute para usar setTimeout y Promise <=> coerción awaitable .
import asyncio
async def async_fn ():
await pm . eval ( """
new Promise((resolve) => setTimeout((...args) => {
console.log(args);
resolve();
}, 1000, 42, "abc")
)
""" )
await pm . eval ( "async (x) => await x" )( asyncio . sleep ( 0.5 ))
asyncio . run ( async_fn ()) Un shell de JavaScript básico, pmjs , barcos con PythonMonkey. Este shell puede actuar como programas replicar o ejecutar JavaScript; Es conceptualmente similar al shell node que se envía con node.js.
PMJS comienza el subsistema CommonJS de PythonMonkey, que le permite usar módulos CommonJS, con semántica que son similares a Node.js, por ejemplo, la búsqueda de módulos.paths, comprensión de paquete.json, index.js, etc. Consulte el módulo CTX para obtener una lista completa de características compatibles.
Además de los módulos CommonJS escritos en JavaScript, PythonMonkey admite módulos CommonJS escritos en Python. Simplemente decore un dict con nombre de exports dentro de un archivo con una extensión .py , y puede cargarse por require() , en JavaScript o Python.
El módulo de programa, o módulo principal, es un módulo especial en CommonJS. En un módulo de programa:
globalThisarguments en una matriz que contiene el vector de argumento de su programa (argumentos de línea de comandos) $ echo " console.log('hello world') " > my-program.js
$ pmjs my-program.js
hello world
$ // date-lib.js - require("./date-lib")
const d = new Date ( ) ;
exports . today = ` ${ d . getFullYear ( ) } - ${ String ( d . getMonth ( ) ) . padStart ( 2 , '0' ) } - ${ String ( d . getDay ( ) ) . padStart ( 2 , '0' ) } ` # date-lib.py - require("./date-lib")
from datetime import date # You can use Python libraries.
exports [ 'today' ] = date . today () Si tiene problemas con la función CommonJS requiere, establecer la variable de entorno DEBUG='ctx-module*' y puede ver los nombres de los archivos que intenta cargar.
PythonMonkey tiene un depurador de línea de comandos JavaScript tipo GDB incorporado llamado PMDB , que se activaría automáticamente en debugger; declaraciones y excepciones no capturas.
Para habilitar PMDB , simplemente llame from pythonmonkey.lib import pmdb; pmdb.enable() Antes de hacer algo en PythonMonkey.
import pythonmonkey as pm
from pythonmonkey . lib import pmdb
pmdb . enable ()
pm . eval ( "..." ) Ejecute el comando help en PMDB para ver los comandos disponibles.
(pmdb) > help
List of commands:
• ...
• ... .help en el replico--help--inspect habilita PMDB , un depurador de línea de comandos JavaScript tipo GDB-r se puede usar para cargar un módulo antes de que su programa o la replica se ejecute-e se puede usar evaluar el código, por ejemplo, definir variables globales, antes de que su programa o el replique se ejecute$1 , $2 , etc. $ pmjs
Welcome to PythonMonkey v1.0.0.
Type ".help" for more information.
> .python import sys
> .python sys.path
$1 = { '0': '/home/wes/git/pythonmonkey2',
'1': '/usr/lib/python310.zip',
'2': '/usr/lib/python3.10',
'3': '/usr/lib/python3.10/lib-dynload',
'4': '/home/wes/.cache/pypoetry/virtualenvs/pythonmonkey-StuBmUri-py3.10/lib/python3.10/site-packages',
'5': '/home/wes/git/pythonmonkey2/python' }
> $1 [3]
'/usr/lib/python3.10/lib-dynload'
>