zopefoundation / RestrictedPython

A restricted execution environment for Python to run untrusted code.
http://restrictedpython.readthedocs.io/
Other
456 stars 38 forks source link

Is it possible to create custom syntax_error_template ? #241

Closed eric-cpp closed 1 year ago

eric-cpp commented 1 year ago

First of all, thank you for this amazing library!

I found the syntax_error_template variable that you are using to output syntax errors:

https://github.com/zopefoundation/RestrictedPython/blob/c1bc989e1fa060273594e39a86d3c4fb3ffe3a4b/src/RestrictedPython/compile.py#L11-L12

Is it possible to customize this template message?

Here's my use case: I need to wrap user's custom code into a python function. It adds a few lines of static code before user's custom code. So if there are any syntax errors in the custom code, the given line number is not correct (because it counts my static code lines), so I would like to subtract N lines from the lineno value.

Is that possible?

loechel commented 1 year ago

@eric-cpp, well it depends how you use RestrictedPython in your Program. If you use a plain call to a restricted_compile* method, you will need to monkey patch that template. If you extend RestrictedPython for your usage you could inherit and overwrite the template.

So yes it is possible, but how hard it is, depends on your program.

eric-cpp commented 1 year ago

Thank you @loechel, that was helpful.

I use a plain call to the compile_restricted method (with a custom policy):

from RestrictedPython import compile_restricted

...

loc = {}
byte_code = compile_restricted(source_code, '<inline>', 'exec', policy=custom_policy)
exec(byte_code, restricted_globals, loc)

result = loc['foo'](data)
print(result)

Is it hard to monkey patch that template? Honestly, I've no idea how to do it in an imported external module...

icemac commented 1 year ago

@eric-cpp You should be able to monkey patch the template like this (Disclaimer: untested code):

from RestrictedPython import compile
compile.syntax_error_template = 'My custom error template -- Line {lineno}'

This is the easy part: This way you cannot change the placeholder values and are not able use different ones without replacing compile_restricted by a custom function.

loechel commented 1 year ago

@eric-cpp you could additionally have a look at https://github.com/zopefoundation/RestrictedPython/blob/master/src/RestrictedPython/transformer.py#L70-L85 on hwo to update the lineno.

if you do have a fixed wrapping code, that should be easily identifiable and remove form the feedback. otherwise, if it is enough to monkypatch the tempalte so that it for example looks like:

'Line {lineno - 5}: {type}: {msg} at statement: {statement!r}'

and fulfils your needs, perfect.

If the questions is thereby solved please close the isse.

eric-cpp commented 1 year ago

@loechel Thank you for all your help!

Yes, I have a fixed wrapping code, so I know the exact number of lines that I need to subtract.

I also thought that I can simply monkey path the syntax_error_template variable like in your example:

from RestrictedPython import compile
compile.syntax_error_template = ('Line {lineno - 5}: {type}: {msg} at statement: {statement!r}')

But it seems that Python doesn't allow to use math operations in the template strings, am I wrong?

loechel commented 1 year ago

sorry, you are right. We do use the old str.format function to pass the data / message. That does not allow to use math statements.

But that is because that specific part was written while we need to support Python 2.7 and 3.5 as well. We could easyly change the code now, that we only support 3.6+ to an f-string template that allows math. that would be fixed by #244

perrinjerome commented 1 year ago

Have you considered patching with an object which implements the format method ?

class CustomSyntaxErrorTemplate:
  def format(self, lineno, type, msg, statement):
    return f'Line {lineno - 5}: {type}: {msg} at statement: {statement!r}' # custom behavior here.

from RestrictedPython import compile
compile.syntax_error_template = CustomSyntaxErrorTemplate()
eric-cpp commented 1 year ago

@perrinjerome Wow! This worked like a charm :) I didn't know this is possible in Python, thank you for sharing this!!

I'm closing this issue as resolved.