diff mercurial/utils/stringutil.py @ 37290:cc5a040fe150

wireproto: syntax for encoding CBOR into frames We just vendored a library for encoding and decoding the CBOR data format. While the intent of that vendor was to support state files, CBOR is really a nice data format. It is extensible and compact. I've been feeling dirty inventing my own data formats for frame payloads. While custom formats can always beat out a generic format, there is a cost to be paid in terms of implementation, comprehension, etc. CBOR is compact enough that I'm not too worried about efficiency loss. I think the benefits of using a standardized format outweigh rolling our own formats. So I plan to make heavy use of CBOR in the wire protocol going forward. This commit introduces support for encoding CBOR data in frame payloads to our function to make a frame from a human string. We do need to employ some low-level Python code in order to evaluate a string as a Python expression. But other than that, this should hopefully be pretty straightforward. Unit tests for this function have been added. Differential Revision: https://phab.mercurial-scm.org/D2948
author Gregory Szorc <gregory.szorc@gmail.com>
date Wed, 28 Mar 2018 15:05:39 -0700
parents 2ed180117f76
children 2f859ad7ed8c
line wrap: on
line diff
--- a/mercurial/utils/stringutil.py	Mon Mar 26 13:59:56 2018 -0700
+++ b/mercurial/utils/stringutil.py	Wed Mar 28 15:05:39 2018 -0700
@@ -9,6 +9,7 @@
 
 from __future__ import absolute_import
 
+import __future__
 import codecs
 import re as remod
 import textwrap
@@ -497,3 +498,29 @@
     If s is not a valid boolean, returns None.
     """
     return _booleans.get(s.lower(), None)
+
+def evalpython(s):
+    """Evaluate a string containing a Python expression.
+
+    THIS FUNCTION IS NOT SAFE TO USE ON UNTRUSTED INPUT. IT'S USE SHOULD BE
+    LIMITED TO DEVELOPER-FACING FUNCTIONALITY.
+    """
+    globs = {
+        r'__builtins__': {
+            r'None': None,
+            r'False': False,
+            r'True': True,
+            r'int': int,
+            r'set': set,
+            r'tuple': tuple,
+            # Don't need to expose dict and list because we can use
+            # literals.
+        },
+    }
+
+    # We can't use eval() directly because it inherits compiler
+    # flags from this module and we need unicode literals for Python 3
+    # compatibility.
+    code = compile(s, r'<string>', r'eval',
+                   __future__.unicode_literals.compiler_flag, True)
+    return eval(code, globs, {})