Commit 57555503 authored by Alexey Stytsenko's avatar Alexey Stytsenko

add calc task

parent 1c711e9c
## CALC
`eval` `input` `namespaces`
### Условие
В этом задании вам нужно написать интерактивный калькулятор, используя функцию `eval`.
При запуске программа должна печатать приглашение к вводу `>>> ` в stdout, читать пользовательский ввод из stdin, выполнять полученное выражение, выводить результат в stdout, и так далее в цикле. Выполнение завершается при получении EOF (см. задачу `input_`).
Выражения должны выполняться в закрытом пространстве имён, в который могут быть предзагружены некоторые объекты, но у калькулятора не должно быть доступа к встроенным функциям из `__builtins__`.
Предполагаем что ввод всегда валидный, обрабатывать ошибки не нужно.
### Пример
```bash
$ python calc.py
>>> 1 + 2
3
>>> [i**2 for i in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> math.cos(math.pi)
-1.0
>>> print(123)
Traceback (most recent call last):
File "calc.py", line 23, in <module>
run_calc(context)
File "calc.py", line 18, in run_calc
print(eval(expr, context))
File "<string>", line 1, in <module>
NameError: name 'print' is not defined
>>>
```
### Что почитать
Почему eval -- зло: https://habr.com/ru/post/221937
import math
from typing import Any, Dict, Optional
PROMPT = '>>> '
def run_calc(context: Optional[Dict[str, Any]] = None) -> None:
"""Run interactive calculator session in specified namespace"""
if __name__ == '__main__':
context = {'math': math}
run_calc(context)
import io
import math
import sys
import pytest
from .calc import run_calc
def test_basic(capsys, monkeypatch): # type: ignore
monkeypatch.setattr(sys, 'stdin', io.StringIO(
'3 + 5\n'
'24 / 2\n'
'math.cos(math.pi)\n'
))
run_calc({'math': math})
captured = capsys.readouterr()
assert captured.out == (
'>>> 8\n'
'>>> 12.0\n'
'>>> -1.0\n'
'>>> \n'
)
def test_context(capsys, monkeypatch): # type: ignore
context = {'foo': lambda x: x * 2}
monkeypatch.setattr(sys, 'stdin', io.StringIO(
'foo(2)\n'
'foo("abc")\n'
'foo([1, 2, 3])\n'
))
run_calc(context)
captured = capsys.readouterr()
assert captured.out == (
'>>> 4\n'
'>>> abcabc\n'
'>>> [1, 2, 3, 1, 2, 3]\n'
'>>> \n'
)
def test_context_error(monkeypatch): # type: ignore
monkeypatch.setattr(sys, 'stdin', io.StringIO(
'math.sqrt(144)\n'
'foo(144)\n'
'print(123)\n'
))
with pytest.raises(NameError, match='name \'math\' is not defined'):
run_calc()
with pytest.raises(NameError, match='name \'foo\' is not defined'):
run_calc()
with pytest.raises(NameError, match='name \'print\' is not defined'):
run_calc()
Subproject commit f7f26beeb16fd2ce2afbe17f9a8489243ae0da8d
Subproject commit 673d358f010fe53bce5d9ecb3901e25f90ce40ff
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