Commit 024787b4 authored by Jérome Perrin's avatar Jérome Perrin

console: fix namespace problems when using slapos console with scripts

When using slapos console on scripts defining functions, for example

```py
def my_request(*args, **kw):
  ...
  return request(*args, **kw)
```

the global names such as `request` where no longer available in the
namespace of the function, because of a wrong usage of exec regarding
locals/globals.
Co-authored-by: Kirill Smelkov's avatarKirill Smelkov <kirr@nexedi.com>
parent 21504241
Pipeline #25477 failed with stage
in 0 seconds
Changes Changes
======= =======
1.8.6 (unreleased)
------------------
* console: fix namespace problems when using slapos console with scripts
1.8.5 (2022-12-14) 1.8.5 (2022-12-14)
------------------ ------------------
* slapos: Update SlapOS website's url * slapos: Update SlapOS website's url
......
...@@ -95,7 +95,7 @@ class ConsoleCommand(ClientConfigCommand): ...@@ -95,7 +95,7 @@ class ConsoleCommand(ClientConfigCommand):
with open(args.script_file) as f: with open(args.script_file) as f:
code = compile(f.read(), args.script_file, 'exec') code = compile(f.read(), args.script_file, 'exec')
local['__file__'] = args.script_file local['__file__'] = args.script_file
return exec_(code, globals(), local) return exec_(code, local, local)
if not any([args.python, args.ipython, args.bpython]): if not any([args.python, args.ipython, args.bpython]):
args.ipython = True args.ipython = True
......
...@@ -802,6 +802,29 @@ print(request('software_release', 'instance').getInstanceParameterDict()['parame ...@@ -802,6 +802,29 @@ print(request('software_release', 'instance').getInstanceParameterDict()['parame
mock_request.assert_called_once_with( mock_request.assert_called_once_with(
'software_release', 'instance') 'software_release', 'instance')
def test_console_script_global_namespace(self):
script = textwrap.dedent('''\
from __future__ import print_function
variable = 'OK'
def f():
print('slapos short-hand names',
'OK' if supply is not None and request is not None else 'PROBLEM')
# namespace behave normally:
print('non local variables', variable)
print('builtins', 'OK' if str is not None else 'PROBLEM')
f()
''')
with tempfile.NamedTemporaryFile(mode='w', suffix='.py') as script_file, \
patch.object(sys, 'stderr', StringIO()) as stderr, \
self._test_console() as (app, config_file, _, stdout):
script_file.write(script)
script_file.flush()
app.run(('console', '--cfg', config_file, script_file.name))
self.assertNotIn('ERROR', stderr.getvalue())
self.assertIn('slapos short-hand names OK', stdout.getvalue())
self.assertIn('non local variables OK', stdout.getvalue())
self.assertIn('builtins OK', stdout.getvalue())
def test_console_script__file__(self): def test_console_script__file__(self):
with self._test_console() as (app, config_file, _, stdout),\ with self._test_console() as (app, config_file, _, stdout),\
tempfile.NamedTemporaryFile('w') as script: tempfile.NamedTemporaryFile('w') as script:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment