Introduction & Objectives
Welcome to Lab Task 1 for Computer Programming 2! In this lab, you will set up a virtual environment, install a GUI library, and build a calculator that deliberately avoids eval(). Instead, you will implement a safe expression evaluator. You will also add a History panel that records the last five calculations.
By the end of this lab, you will be able to:
- Create and manage a project-specific Python virtual environment.
- Use pip to install an external library and generate a
requirements.txt. - Build a FreeSimpleGUI application with multiple layout elements.
- Implement a safe expression evaluator that does not use
eval(). - Critically compare a safe parser with the
eval()approach.
Materials Required
- A computer with Python 3 installed.
- A code editor (Visual Studio Code, Sublime Text, etc.).
- A command line interface (Terminal on macOS/Linux, Command Prompt or PowerShell on Windows).
Lab Procedure
Follow these steps carefully.
Learning Outcome 1: The setup steps below address your ability to analyse an engineering application to facilitate the development of a software solution using RAD techniques. By identifying the required library and documenting it in requirements.txt, you perform an analysis that establishes the software requirements for this application.
-
Step 1: Create a Project Directory
Create a new directory called
safe-calculatorand navigate into it.mkdir safe-calculator cd safe-calculator -
Step 2: Create the Virtual Environment
Create a virtual environment named
venvinside your project directory.python -m venv venvNote: On some systems you may need to usepython3instead ofpython. -
Step 3: Activate the Virtual Environment
On Windows:
venv\Scripts\activateOn macOS / Linux:
source venv/bin/activateThe
(venv)prefix will appear in your prompt once activated. -
Step 4: Install FreeSimpleGUI
Install the GUI library using pip. Because the virtual environment is active, this installs only into your project environment.
pip install FreeSimpleGUI -
Step 5: Create a
requirements.txtFileRecord your project's dependencies with the following command:
pip freeze > requirements.txtOpen the file — you should see
FreeSimpleGUIand its version number listed. -
Step 6: Write the Calculator Code
Create a file named
calculator_app.pyinside yoursafe-calculatordirectory. The calculator must meet the following requirements:- Standard digit and operator buttons (0–9, +, -, *, /, ., C, =).
- An Input display widget showing the current expression.
- A Multiline widget labelled "History" that shows the last 5 expressions and their results.
- The computation on
=must use a safe evaluator — noteval(). You may use one of the approaches below.
Security requirement: Usingeval()(orexec()) anywhere in your solution will result in a significant mark deduction. Choose one of the safe alternatives described below.Recommended safe approach — operator dispatch:
import operator as op # Map operator symbols to functions OPS = { '+': op.add, '-': op.sub, '*': op.mul, '/': op.truediv, } def safe_evaluate(expression): """ Evaluate a simple two-operand expression such as '12.5 + 7'. Returns the numeric result, or raises ValueError for invalid input. Only handles a single binary operation (no nested parentheses). """ for symbol in ('+', '-', '*', '/'): if symbol in expression: parts = expression.split(symbol, 1) if len(parts) == 2: left = float(parts[0].strip()) right = float(parts[1].strip()) if symbol == '/' and right == 0: raise ZeroDivisionError("Division by zero") return OPS[symbol](left, right) # If no operator found, try to return a plain number return float(expression.strip())Alternative approach —
astmodule: You may instead use Python'sastmodule to parse the expression tree and evaluate it without executing arbitrary code. Researchast.parse()andast.literal_eval()if you choose this route.Below is the starter structure for the full application. Complete the
# TODOsections:import FreeSimpleGUI as sg import operator as op # Safe operator dispatch (or replace with your ast-based approach) OPS = {'+': op.add, '-': op.sub, '*': op.mul, '/': op.truediv} def safe_evaluate(expression): """Evaluate a simple binary arithmetic expression without using eval().""" # TODO: implement safe evaluation logic (see example above) pass sg.theme('DarkTeal9') # History stores the last 5 calculation strings history = [] layout = [ # Display row [sg.Input(size=(30, 1), font=('Helvetica', 18), justification='right', key='-DISPLAY-', readonly=True)], # Button rows [sg.Button('C', size=(4,2)), sg.Button('(', size=(4,2)), sg.Button(')', size=(4,2)), sg.Button('/', size=(4,2))], [sg.Button('7', size=(4,2)), sg.Button('8', size=(4,2)), sg.Button('9', size=(4,2)), sg.Button('*', size=(4,2))], [sg.Button('4', size=(4,2)), sg.Button('5', size=(4,2)), sg.Button('6', size=(4,2)), sg.Button('-', size=(4,2))], [sg.Button('1', size=(4,2)), sg.Button('2', size=(4,2)), sg.Button('3', size=(4,2)), sg.Button('+', size=(4,2))], [sg.Button('0', size=(9,2)), sg.Button('.', size=(4,2)), sg.Button('=', size=(4,2))], # History panel [sg.Text('History:')], [sg.Multiline('', size=(30, 5), key='-HISTORY-', disabled=True, font=('Courier New', 10))], ] window = sg.Window('Safe Calculator', layout) current_expression = '' while True: event, values = window.read() if event == sg.WIN_CLOSED: break if event == 'C': current_expression = '' window['-DISPLAY-'].update('0') elif event == '=': try: result = safe_evaluate(current_expression) result_str = str(result) # TODO: add "expression = result" to history list (keep last 5) window['-DISPLAY-'].update(result_str) window['-HISTORY-'].update('\n'.join(history)) current_expression = result_str except ZeroDivisionError: window['-DISPLAY-'].update('Div/0 Error') current_expression = '' except Exception: window['-DISPLAY-'].update('Error') current_expression = '' else: current_expression += event window['-DISPLAY-'].update(current_expression) window.close() -
Step 7: Run Your Application
Save
calculator_app.pyand run it with your virtual environment active:python calculator_app.pyTest the calculator. Verify that the History panel updates after each calculation and that all four arithmetic operations work.
-
Step 8: Deactivate the Virtual Environment
deactivate
Learning Outcome 2: The following step addresses your ability to develop a software solution for an engineering application using RAD techniques. You will use FreeSimpleGUI components to build the calculator UI and implement a safe expression parser, demonstrating effective and efficient use of the library's RAD capabilities.
Evaluation and Reflection
Learning Outcome 3: This section addresses your ability to evaluate the performance of a RAD software solution to an engineering application. You must technically appraise the performance of your application, use informed judgement to identify deficiencies, and propose improvements.
Answer the following questions in a separate document (PDF or .txt). Your answers should be concise but thorough.
-
Appraise Security: Your safe evaluator rejects arbitrary input like
__import__('os').system('ls'). Run this string through yoursafe_evaluate()function (test it in a Python shell, not in the GUI) and describe what happens. Does your evaluator raise an exception, return an error, or behave unexpectedly? Explain why your approach is safer thaneval()for this input. -
Compare Approaches: Compare the
eval()-based calculator from the original lab with your safe-parser implementation. Discuss the security trade-off and the maintainability trade-off — in what situations might each approach be acceptable? - Identify Areas for Improvement: Your current safe evaluator handles only a single binary operation. Propose one concrete enhancement — for example, support for operator precedence, parentheses, or unary negation. Describe the logic of your proposed enhancement without writing the code.
Lab Submission
Submit the following files:
- Your Python script: calculator_app.py
- Your dependency file: requirements.txt
- A screenshot of the running application showing at least two completed calculations in the History panel.
- A document (PDF or .txt) with your answers to the three Evaluation questions.
Troubleshooting
Problem: ModuleNotFoundError: No module named 'FreeSimpleGUI'
Solution: Your virtual environment is not active. Run the activation command from Step 3 again and look for the (venv) prefix before re-running the script.
Problem: The calculator shows Error for expressions like 3+4*2.
Solution: The operator-dispatch approach above only handles a single operator. Split the expression on the first operator found. If you want to support compound expressions, look into the shunting-yard algorithm or the ast module.