Skip to content

Instantly share code, notes, and snippets.

@atdt
Last active December 16, 2015 05:08
Show Gist options
  • Save atdt/5382043 to your computer and use it in GitHub Desktop.
Save atdt/5382043 to your computer and use it in GitHub Desktop.
Scribunto REPL. Uses MediaWiki API to evaluates Lua code in remote MediaWiki context.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Scribunto REPL (interactive Lua interpreter)
--------------------------------------------
Uses MediaWiki's API to evaluates Lua code in a remote MediaWiki context. Run
with no arguments to evaluate code against Module:Sandbox on MediaWiki.org.
Usage:
scrib [-h] [--module MODULE] [--file FILE] [--api API]
Optional arguments:
-h, --help show this help message and exit
--module MODULE Module to load (default: Module:Sandbox)
--file FILE Lua file containing updated module code
--api API Full URL to api.php (default: http://mediawiki.org/w/api.php)
Written by Ori Livneh <ori@wikimedia.org>
"""
import argparse
import code
import json
import urllib
import urllib2
try:
import readline
except ImportError:
pass
red = lambda s: '\033[91m%s\033[0m' % s
yellow = lambda s: '\033[93m%s\033[0m' % s
class ScribuntoRepl(code.InteractiveConsole):
"""Interactive Scribunto REPL.
Evaluates Lua code in remote MediaWiki context."""
params = {
'action': 'scribunto-console',
'format': 'json',
}
def __init__(self, module='Module:Sandbox', content=None,
api='http://www.mediawiki.org/w/api.php'):
code.InteractiveConsole.__init__(self)
self.api = api
# Canonicalize module name
if not module.startswith('Module:'):
module = 'Module:' + module
self.params['title'] = module
if content is not None:
self.params.update(content=content)
self.runsource('=', fatal=True)
self.params.pop('content')
def runsource(self, source, *args, **kwargs):
query = dict(self.params, question=source)
try:
req = urllib2.urlopen(self.api + '?' + urllib.urlencode(query))
resp = json.load(req)
self.params['session'] = resp['session']
except (IOError, KeyError, ValueError) as e:
raise IOError('Failed to retrieve or decode API response: %s' % e)
if resp.get('type') == 'normal':
output = resp.get('print', resp['return'])
self.write(output)
else:
msg = resp.get('message', 'Unknown error')
if kwargs.get('fatal', False):
raise SystemExit(msg)
self.write(red(msg) + '\n')
return False
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='An interactive Scribunto interpreter',
epilog=('By default, evaluates code with mediawiki.org/wiki/'
'Module:Sandbox as context.'))
parser.add_argument(
'--module',
default='Module:Sandbox',
help='Module to load (default: Module:Sandbox)'
)
parser.add_argument(
'--file',
type=argparse.FileType('r'),
help='Lua file containing updated module code'
)
parser.add_argument(
'--api',
default='http://www.mediawiki.org/w/api.php',
help='URL to api.php (default: http://mediawiki.org/w/api.php)'
)
args = parser.parse_args()
content = None
if args.file is not None:
content = args.file.read()
args.file.close()
print(yellow('Scribunto REPL') + '\n')
print('* The module exports are available as the variable "p", including unsaved modifications.')
print('* Precede a line with "=" to evaluate it as an expression, or use print().')
print('* Use mw.log() in module code to send messages to this console.')
repl = ScribuntoRepl(module=args.module, content=content, api=args.api)
repl.interact('')
# vim set ft=python et sw=4 sts=4:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment