Niestandardowy koder JSON w Pythonie 2.7 do wstawiania zwykłego kodu JavaScript

Usiłuję uaktualnić część kodu Pythona 2.6 do Pythona 2.7. Ten kod używajson moduł do tworzenia JavaScript (nie zgodny z JSON), który jest następnie wstawiany do reszty skryptu.

Ogólną ideą jest możliwość wstawienia kodu lub odwoływania się do zmiennych zdefiniowanych gdzie indziej: nie jest przeznaczony do użycia jako dane JSON, ale kod JavaScript.

Oto niestandardowy koder, który działa w Pythonie 2.6:

import json

class RawJavaScriptText:
    def __init__(self, jstext):
        self._jstext = jstext
    def get_jstext(self):
        return self._jstext

class RawJsJSONEncoder(json.JSONEncoder):
    def _iterencode_default(self, o, markers=None):
        if isinstance(o, RawJavaScriptText):
            yield self.default(o)
        else:
            json.JSONEncoder._iterencode_default(self, o, markers)

    def default(self, o):
        if isinstance(o, RawJavaScriptText):
            return o.get_jstext()
        else:
            return json.JSONEncoder.default(self, o)

testvar = {
   'a': 1,
   'b': 'abc',
   # RawJavaScriptText will be inserted as such, no serialisation.
   'c': RawJavaScriptText('function() { return "Hello World"; }'),
   'd': RawJavaScriptText('some_variable_name')
}

print json.dumps(testvar, cls=RawJsJSONEncoder)

Korzystając z Pythona 2.6, uzyskujemy wymagany wynik:

{ "a": 1, "c": function() { return "Hello World"; },
  "b": "abc", "d": some_variable_name }

Używając Pythona 2.7, wszystko jest przekształcane w ciąg znaków, tracąc tym samym ważność kodu JavaScript:

{ "a": 1, "c": "function() { return \"Hello World\"; }",
  "b": "abc", "d": "some_variable_name" }

(Na marginesie, jest to używane tylko z predefiniowanym zestawem surowej wartości JavaScript, aby zapobiec potencjalnym zastrzykom lub niewłaściwemu użyciu).

Oczywiście powodem tego jest_iterencode_default metodaJSONEncoder nie istnieje w wersji Pythona 2.7json moduł. Trzeba przyznać, że w pierwszej kolejności nie miało to być zastąpione.

Czy istnieje inny sposób osiągnięcia tego celu w Pythonie 2.7? Korzystanie z fundamentów biblioteki JSON w celu generowania kodu JavaScript w ten sposób jest raczej wygodne.

EDYTOWAĆ: Oto kompletne rozwiązanie robocze, z wykorzystaniem wymiany, jak sugeruje James Henstridge. Używam losowych identyfikatorów UUID dla żetonów zastępczych, co powinno zapobiec wszelkim konfliktom. W ten sposób jest to bezpośredni zamiennik działający z Pythonem 2.6 i 2.7.

import json
import uuid

class RawJavaScriptText:
    def __init__(self, jstext):
        self._jstext = jstext
    def get_jstext(self):
        return self._jstext

class RawJsJSONEncoder(json.JSONEncoder):
    def __init__(self, *args, **kwargs):
        json.JSONEncoder.__init__(self, *args, **kwargs)
        self._replacement_map = {}

    def default(self, o):
        if isinstance(o, RawJavaScriptText):
            key = uuid.uuid4().hex
            self._replacement_map[key] = o.get_jstext()
            return key
        else:
            return json.JSONEncoder.default(self, o)

    def encode(self, o):
        result = json.JSONEncoder.encode(self, o)
        for k, v in self._replacement_map.iteritems():
             result = result.replace('"%s"' % (k,), v)
        return result

testvar = {
   'a': 1,
   'b': 'abc',
   'c': RawJavaScriptText('function() { return "Hello World"; }'),
   'd': [ RawJavaScriptText('some_variable_name') ],
   'e': {
       'x': RawJavaScriptText('some_variable_name'),
       'y': 'y'
   }
}

print json.dumps(testvar, cls=RawJsJSONEncoder)

Wynik (2.6 i 2.7):

{"a": 1, "c": function() { return "Hello World"; },
 "b": "abc",
 "e": {"y": "y", "x": some_variable_name},
 "d": [some_variable_name]}

questionAnswers(1)

yourAnswerToTheQuestion