PythonMonkey est un moteur JavaScript Mozilla Spidermonkey intégré à l'exécution de Python, en utilisant le moteur Python pour fournir l'environnement hôte JavaScript.
Nous présentons un tableau JavaScript et des méthodes d'objets implémentées sur la liste Python et les dictionnaires à l'aide de l'API CPYthon C, et l'inverse à l'aide de l'API C ++ JavaScript C ++ de Mozilla Firefox.
Ce projet a atteint MVP en septembre 2024. Il est sous maintenance par distribution.
Les contributions externes et les commentaires sont les bienvenues et encouragées.
$ pip install pythonmonkey from pythonmonkey import eval as js_eval
js_eval ( "console.log" )( 'hello, world' )eval() dans Python qui accepte le code JS et renvoie JS-> Python CORCED VALEURSrequire une fonction, renvoie un dict contrainte des exportations de modulesLisez ceci si vous souhaitez créer une version locale.
Vous aurez besoin de l'installation suivante (ce qui peut être effectué automatiquement en exécutant ./setup.sh ):
Exécutez poetry install . Cette commande compile automatiquement le projet et installe le projet ainsi que les dépendances dans la poésie virtualenv. Si vous souhaitez construire les documents, définissez la variable d'environnement BUILD_DOCS , comme ainsi: BUILD_DOCS=1 poetry install . PythonMonkey prend en charge plusieurs types de build, que vous pouvez créer en définissant la variable d'environnement BUILD_TYPE , comme ainsi: BUILD_TYPE=Debug poetry install . Les types de construction sont (insensibles à la casse):
Release : Symboles dépouillés, optimisations maximales (par défaut)DRelease : Identique à Release , sauf que les symboles ne sont pas éliminésDebug : optimisations minimalesSanitize : Identique que Debug , sauf avec Addresssanitizer activéProfile : Identique au Debug , sauf le profilage est activéNone : ne compilez pas (utile si vous voulez seulement construire les documents) Si vous utilisez VScode, vous pouvez simplement appuyer sur Ctrl + Shift + B pour exécuter la tâche de construction - nous avons le fichier tasks.json configuré pour vous.
poetry install --no-root --only=devpoetry run pytest ./tests/pythonpoetry run bash ./peter-jr ./tests/js/Pour les utilisateurs de VScode, similaires à la tâche de construction, nous avons une tâche de test prête à l'emploi.
NPM (Node.js) est requis lors de l'installation uniquement pour remplir les dépendances JS.
$ pip install pythonmonkey$ pip install --extra-index-url https://nightly.pythonmonkey.io/ --pre pythonmonkey pythonmonkey est disponible dans la poésie virtualenv une fois que vous avez compilé le projet à l'aide de la poésie.
$ 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!'Alternativement, vous pouvez créer des packages installables en exécutant
$ cd python/pminit && poetry build --format=sdist && cd - && mv -v python/pminit/dist/ * ./dist/
$ poetry build --format=wheel et les installer par pip install ./dist/* .
L'installation pythonmonkey installera également le package pminit comme dépendance. Cependant, pip uninstall un package ne supprimera pas automatiquement ses dépendances.
Si vous souhaitez supprimer proprement pythonmonkey de votre système, procédez comme suit:
$ pip uninstall pythonmonkey pminitpoetry run gdb python . Voir Python Wiki: Débogging withgdb Si vous utilisez VScode, il est plus pratique de déboguer dans le débogueur intégré de VScode. Appuyez simplement sur F5 sur un fichier Python ouvert dans l'éditeur pour démarrer le débogage - nous avons le fichier launch.json configuré pour vous.
Ces méthodes sont exportées du module PythonMonkey. Voir Définitions dans Python / PythonMonkey / PythonMonkey.pyi.
Évaluez le code JavaScript. La sémantique de cette évaluation est très similaire à l'évaluation utilisée en JavaScript; La dernière expression évaluée dans la chaîne code est utilisée comme valeur de retour de cette fonction. Pour évaluer code en mode strict, la première expression doit être la chaîne "use strict" .
La fonction EVAL prend en charge un objet Options qui peut affecter la façon dont le code JS est évalué de manière puissante. Ils sont en grande partie basés sur CompileOptions de Spidermonkey. Les clés d'option prise en charge sont:
filename : Définissez le nom de fichier de ce code dans le but de générer des traces de pile, etc.lineno : Définissez le décalage du numéro de ligne de ce code aux fins de la génération de traces de pile, etc.column : Définissez le décalage du numéro de colonne de ce code à des fins de génération de traces de pile, etc.mutedErrors : Si défini sur True , évaluez les erreurs ou les rejets non gérés sont ignorés ("muet"). Par défaut False .noScriptRval : si False , renvoyez la dernière valeur d'expression du script comme valeur de résultat à l'appelant. Par défaut False .selfHosting : expérimentalstrict : évaluer de force en mode strict ( "use strict" ). Par défaut False .module : indiquez que le fichier est un module ECMAScript (toujours le code de mode strict et interdit les commentaires HTML). Par défaut False .fromPythonFrame : Générez l'équivalent du nom de fichier, du lineno et de la colonne basée sur l'emplacement de l'appel Python à l'évaluation. Cela permet d'évaluer les littéraux de chaînes multilines Python et de générer des traces de pile dans JS pointant vers l'erreur dans le fichier source Python. undefined en JavaScript; Si vous souhaitez renvoyer une fonction, vous devez évaluer une expression: pythonmonkey . eval ( "myFunction() { return 123 }; myFunction" ) pythonmonkey . eval ( "(myFunction() { return 123 })" ) pythonmonkey . eval ( "(thing) => console.log('you said', thing)" )( "this string came from Python" ) Renvoyez les exportations d'un module CommonJS identifié par moduleIdentifier , en utilisant la sémantique Standard CommonJS
require.js - module JavaScript; Le code source décorait l'objet exports.py - module Python; Le code source décore exports.json - Module JSON; Les exportations sont le résultat de l'analyse du texte JSON dans le fichierUn dict Python qui équivaut à l'objet Global This en JavaScript.
Fonction d'usine qui renvoie une nouvelle fonction exige
Charge et évaluer un module de programme (principal). Les modules de programme doivent être écrits en javascript. Les modules de programme ne sont pas nécessaires à moins que le point d'entrée principal de votre programme soit écrit en JavaScript.
Il faut veiller à ce qu'un seul module de programme soit exécuté par contexte JS.
Examine le code de chaîne et renvoie Faux si la chaîne peut devenir une instruction JS valide avec l'ajout de plus de lignes. Ceci est utilisé en interne par PMJS et peut être très utile pour construire des réponses JavaScript; L'idée est d'accumuler des lignes dans un tampon jusqu'à ce que ISCOMPilable Unit soit vrai, puis évalue l'ensemble du tampon.
Renvoie une fonction Python qui invoque function avec le nouvel opérateur 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
{}
>> > Il s'agit de l'opérateur JS typeof , enveloppé dans une fonction afin qu'il puisse être utilisé facilement à partir de Python.
Toutes les classes standard JS (tableau, fonction, objet, date ...) et objets (GlobalThis, finalisationRegistry ...) sont disponibles sous forme d'exportations du module Pythonmonkey. Ces exportations sont générées en énumérant la variable globale dans le contexte actuel de SpiderMonkey. La liste actuelle est:
Undefined, booléen, json, date, mathématiques, numéro, chaîne, regexp, erreur, intercarrotte, agrégaterror, évaluorror, gangeerror, référence, syntaxerror, type. Float64Array, uint8clampedArray, bigInt64Array, bigUint64Array, bigint, proxy, faiblemap, map, set, dataView, symbol, intl, réflexion, faiblet, promesse, webassembly, faiblef, itérateur, asynciterator, nan, infinity, iSnan, isfinite encodéuri, décodérucomposant, encoceuriComponent, fonction, objet, debuggerglobal, finalisationgistry, array, globalthis
Voir Définitions dans Python / PythonMonkey / Global.d.ts. Y compris:
consoleatobbtoasetTimeoutclearTimeout Le sous-système CommonJS est activé en invoquant les exportations require ou createRequire du module (python) pythonmonkey.
requireexportsmodule__filename__dirnamepython.print - La fonction d'impression Pythonpython.getenv - La fonction Python Getenvpython.stdout - un objet avec des méthodes read et write , qui lisent et écrivent à stdoutpython.stderr - un objet avec des méthodes read et write , qui lisent et écrivent à STDERRpython.exec - la fonction exec Pythonpython.eval - la fonction Python Evalepython.exit - exit via sys.exit (); Le code de sortie est l'argument de la fonction ou python.exit.code .python.paths - La liste des cheminées Python Sys, visible en js comme un tableau Lors de l'envoi de variables de Python dans JavaScript, PythonMonkey coercera ou enveloppera intelligemment vos variables en fonction de leur type. PythonMonkey partagera les magasins d'accompagnement (utilisez la même mémoire) pour les CTYPES, les tableaux typés et les chaînes; Déplacer ces types à travers la barrière de la langue est extrêmement rapide car il n'y a pas de copie.
Remarque: Il y a des plans dans Python 3.12 (PEP 623) pour modifier la représentation de la chaîne interne afin que chaque caractère de la chaîne utilise quatre octets de mémoire. Cela cassera les transferts de chaîne rapides pour PythonMonkey, car il s'appuie sur la disposition de la mémoire étant la même dans Python et JavaScript. À ce jour (juillet 2023), les chaînes de python "classiques" fonctionnent toujours dans les versions bêta 3.12.
Lorsque le magasin de support partagé n'est pas possible, PythonMonkey émettra automatiquement des emballages qui utilisent la structure de données "réelle" comme autorité de valeur. Seules les intrinsèques immuables sont copiés. Cela signifie que si vous mettez à jour un objet en JavaScript, le dict correspondant dans Python sera mis à jour, etc.
Les méthodes de tableau et d'objets JavaScript sont implémentés sur la liste Python et les dictionnaires, et vice-versa.
| Type python | Type javascript |
|---|---|
| Chaîne | chaîne |
| Entier | nombre |
| Bool | booléen |
| Fonction | fonction |
| Diction | objet |
| Liste | Tableau |
| DateTime | Objet Date |
| attendable | Promesse |
| Erreur | Objet d'erreur |
| Tampon | Arraybuffer |
| Type javascript | Type python |
|---|---|
| chaîne | pythonmonkey.jsstringproxy (String) |
| nombre | Flotter |
| grand | pythonmonkey.bigint (entier) |
| booléen | Bool |
| fonction | pythonmonkey.jsfonctionproxy |
| objet - la plupart | pythonmonkey.jsobjectproxy (dict) |
| objet - date | DateTime |
| objet - tableau | pythonmonkey.jsarrayproxy (liste) |
| Objet - Promesse | attendable |
| objet - ArrayBuffer | Tampon |
| Tableaux d'objet - Type | Tampon |
| Objet - Erreur | Erreur |
Vous pouvez forcer un numéro en JavaScript à être contraint comme un entier en le casting à BigInt:
function myFunction ( a , b ) {
const result = calculate ( a , b ) ;
return BigInt ( Math . floor ( result ) ) ;
} L'objet pythonmonkey.bigint fonctionne comme un int dans Python, mais il sera contraint comme un grandint en javascript:
import pythonmonkey
def fn myFunction ()
result = 5
return pythonmonkey . bigint ( result )Vous pouvez utiliser un iife javascript pour créer une portée dans laquelle vous pouvez injecter des symboles 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 ); Vous avez besoin d'une course d'événements en cours pour utiliser setTimeout et Promise <=> La coercition 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 JavaScript de base, pmjs , expédie avec Pythonmonkey. Ce shell peut agir en tant que programmes JavaScript REPO ou exécuter; Il est conceptuellement similaire à la coquille node qui expédie avec Node.js.
PMJS démarre le sous-système CommonJS de PythonMonkey, qui lui permet d'utiliser des modules CommonJS, avec une sémantique similaire à Node.js - par exemple Module.Paths, compréhension package.json, index.js, etc. Voir le module CTX pour une liste complète des fonctionnalités prises en charge.
En plus des modules CommonJS écrits en javascript, PythonMonkey prend en charge les modules CommonJS écrits en python. Décorez simplement un dict nommé exports dans un fichier avec une extension .py , et il peut être chargé par require() - dans JavaScript ou Python.
Le module de programme, ou module principal, est un module spécial dans CommonJS. Dans un module de programme:
globalThisarguments dans un tableau qui contient le vecteur d'argument de votre programme (arguments en ligne de commande) $ 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 vous rencontrez des problèmes avec la fonction CommonJS, définissez la variable d'environnement DEBUG='ctx-module*' et vous pouvez voir les noms de fichiers qu'il essaie de charger.
PythonMonkey a un débogueur de ligne de commande JavaScript de type GDB intégré appelé PMDB , qui serait automatiquement déclenché sur debugger; déclarations et exceptions non revues.
Pour activer PMDB , appelez simplement from pythonmonkey.lib import pmdb; pmdb.enable() avant de faire quoi que ce soit sur Pythonmonkey.
import pythonmonkey as pm
from pythonmonkey . lib import pmdb
pmdb . enable ()
pm . eval ( "..." ) Exécutez la commande help dans PMDB pour voir les commandes disponibles.
(pmdb) > help
List of commands:
• ...
• ... .help--help--inspect permet PMDB , un débogueur de ligne de commande JavaScript de type GDB-r peut être utilisée pour charger un module avant votre programme ou les REP s'exécutent-e peut être utilisée d'évaluation du code - par exemple, définissez les variables globales - avant votre programme ou les REP exécutés$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'
>