What the ESP is
| Assessment | Content | Format | Weighting |
|---|---|---|---|
| Employer Set Project | Synoptic: draws on all core content | Supervised project up to 14 h 30 min, 100 marks. Tasks: planning, fixing defects in code, design, development, reflective evaluation. No internet or AI tools. | 40% |
Pre-release material comes out before the tasks start. It introduces the employer's scenario, so read it carefully and make sure you understand the business, its users and the problem.
Key dates
From the course key dates (provisional, so check with your teacher).
| Date | What | Details |
|---|---|---|
| Loading... | ||
✗ NO INTERNET OR AI TOOLS
You won't be able to look anything up during the tasks. Practise now so you don't need to:
- Learn the Appendix 2 Python commands: they're the ones you can expect to need.
- Write code without autocomplete or AI suggestions, then run and debug it yourself.
- Get quick at reading Python error messages: the error type and line number tell you where to look (2.10).
- Know the pandas and matplotlib basics below by heart.
What to revise for each kind of task
The ESP tasks cover planning, fixing defects, design, development and reflective evaluation. This table shows which parts of the guide help most with each. It's revision guidance, not the official mark scheme.
| Kind of task | What you'll be doing | Revise |
|---|---|---|
| Planning | Breaking the brief down, working out requirements and what the solution needs to do | Decomposition and abstraction (1.1), problem-solving strategies (1.3), SMARTER objectives (5.4.4), feasibility (5.4.5) |
| Fixing defects in code | Finding and correcting errors in code you're given | Debugging and error types (2.10), testing and test data (2.12), practice below |
| Design | Planning the solution before you build it | Flowcharts and written algorithms (1.2), data models (6.10), end users and accessibility (3.1.3), design considerations (2.9) |
| Development | Writing and testing the code | All of CA2, validation (2.8), robust code (2.10), pandas and matplotlib, security |
| Reflective evaluation | Judging how well your solution meets the brief, and how you'd improve it | Judging an algorithm (2.9.7), command words and the explanation ladder, evaluation guide below |
pandas and matplotlib
The spec lists these for the Employer Set Project only: pandas (import CSV, data frames, totals, averages, counts, trends) and matplotlib (graphs with labels and legends). Press ▶ Run on each example to try it: the first run loads pandas, which takes a little longer. Run the examples in order, because example 1 creates the file the others read.
1. Import a CSV into a data frame
A data frame is a table: rows are records, columns are fields. pd.read_csv() turns a CSV file into one, and works out the data types for you.
import pandas as pd
with open("sales.csv", "w") as f:
f.write("date,branch,item,quantity,price\n")
f.write("2027-05-03,Leeds,Latte,12,3.20\n")
f.write("2027-05-03,York,Tea,8,1.80\n")
f.write("2027-05-04,Leeds,Scone,5,2.50\n")
f.write("2027-05-04,York,Latte,9,3.20\n")
f.write("2027-05-05,Leeds,Latte,15,3.20\n")
f.write("2027-05-05,York,Scone,11,2.50\n")
sales = pd.read_csv("sales.csv")
print(sales.head(3))
print(len(sales), "rows,", len(sales.columns), "columns")
date branch item quantity price
0 2027-05-03 Leeds Latte 12 3.2
1 2027-05-03 York Tea 8 1.8
2 2027-05-04 Leeds Scone 5 2.5
6 rows, 5 columns
head(3) shows the first 3 rows. The numbers down the left are the index. Unlike the plain csv module (6.5), pandas reads numbers as numbers, not strings.
2. Totals, averages and counts
import pandas as pd
sales = pd.read_csv("sales.csv")
sales["total"] = sales["quantity"] * sales["price"]
print("Total takings: £" + format(sales["total"].sum(), ".2f"))
print("Average quantity:", round(sales["quantity"].mean(), 1))
print("Biggest sale: £" + format(sales["total"].max(), ".2f"))
print(sales["item"].value_counts())
Total takings: £169.60 Average quantity: 10.0 Biggest sale: £48.00 item Latte 3 Scone 2 Tea 1 Name: count, dtype: int64
| Code | What it does |
|---|---|
df["new"] = df["a"] * df["b"] | Adds a calculated column, working out every row at once |
.sum() .mean() .max() .min() | Total, average, largest and smallest of a column |
.value_counts() | How many times each value appears |
len(df) | Number of rows |
3. Group, filter and sort
import pandas as pd
sales = pd.read_csv("sales.csv")
sales["total"] = sales["quantity"] * sales["price"]
print(sales.groupby("branch")["total"].sum())
print()
lattes = sales[sales["item"] == "Latte"]
print(lattes[["date", "branch", "quantity"]])
print()
print(sales.sort_values("total", ascending=False).head(2))
branch
Leeds 98.9
York 70.7
Name: total, dtype: float64
date branch quantity
0 2027-05-03 Leeds 12
3 2027-05-04 York 9
4 2027-05-05 Leeds 15
date branch item quantity price total
4 2027-05-05 Leeds Latte 15 3.2 48.0
0 2027-05-03 Leeds Latte 12 3.2 38.4
| Code | What it does |
|---|---|
df.groupby("col")["other"].sum() | A total for each group, e.g. takings per branch |
df[df["col"] == value] | Only the rows that match a condition (a filter) |
df[["a", "b"]] | Only some columns (note the double brackets) |
df.sort_values("col", ascending=False) | Sort the rows, largest first |
4. Show a trend with a labelled graph
import pandas as pd
import matplotlib.pyplot as plt
sales = pd.read_csv("sales.csv")
sales["total"] = sales["quantity"] * sales["price"]
daily = sales.groupby(["date", "branch"])["total"].sum().unstack()
print(daily)
daily.plot(kind="line", marker="o")
plt.title("Daily takings by branch")
plt.xlabel("Date")
plt.ylabel("Takings (£)")
plt.legend(title="Branch")
plt.tight_layout()
plt.savefig("takings.png")
print("Chart saved as takings.png")
branch Leeds York date 2027-05-03 38.4 14.4 2027-05-04 12.5 28.8 2027-05-05 48.0 27.5 Chart saved as takings.png
When you run it here, the chart appears under the output. On your own computer, plt.show() opens it in a window instead of saving it.
★ EVERY GRAPH NEEDS
- A title that says what the graph shows:
plt.title() - Labelled axes, with units:
plt.xlabel()andplt.ylabel() - A legend whenever there's more than one line or bar colour:
plt.legend() - The right type: a line graph for trends over time, a bar chart to compare categories (6.9)
▲ TRY IT
- Change example 4 to
kind="bar". Which chart shows the trend more clearly? - Add a line to example 2 that prints the average takings per sale.
- Filter example 3 to show only York's sales of more than £20.
Fixing defects: practice
Each program has defects. For each one, give the line number, the problem, the type of error (syntax, runtime or logic) and the corrected line. Press ▶ Run to watch the faulty code fail, then fix it in the editor until it works.
This program should print the average score and how many scores are 50 or more. Find the three defects.
scores = [72, 45, 50, 88, 39]
total = 0
passes = 0
for score in scores:
total = total + score
if score > 50:
passes = passes + 1
average = total / len(score)
print("Average: " + average)
print("Scores of 50 or more:", passes)
| Line | Defect | Type | Correction |
|---|---|---|---|
| 6 | > 50 leaves out a score of exactly 50 | Logic | if score >= 50: |
| 8 | len(score) uses the single score (an int), not the list | Runtime (TypeError) | average = total / len(scores) |
| 9 | Joins a float to a string with + | Runtime (TypeError) | print("Average: " + str(average)) |
One mark for each defect found, one for each correct fix.
scores = [72, 45, 50, 88, 39]
total = 0
passes = 0
for score in scores:
total = total + score
if score >= 50:
passes = passes + 1
average = total / len(scores)
print("Average: " + str(average))
print("Scores of 50 or more:", passes)
Average: 58.8 Scores of 50 or more: 3
This program should count how many times each colour appears. Find the two defects.
colours = ["red", "blue", "red", "green", "blue", "red"]
counts = {}
for colour in colours:
if colour in counts:
counts[colour] = 1
else:
counts[colour] = counts[colour] + 1
for colour, number in counts.items:
print(colour, number)
| Line | Defect | Type | Correction |
|---|---|---|---|
| 5 and 7 | The two branches are the wrong way round: a new colour isn't in the dictionary yet, so line 7 raises a KeyError | Runtime (KeyError) | Line 5: counts[colour] = counts[colour] + 1; line 7: counts[colour] = 1 |
| 8 | counts.items is missing its brackets, so it isn't called | Runtime (TypeError) | for colour, number in counts.items(): |
colours = ["red", "blue", "red", "green", "blue", "red"]
counts = {}
for colour in colours:
if colour in counts:
counts[colour] = counts[colour] + 1
else:
counts[colour] = 1
for colour, number in counts.items():
print(colour, number)
red 3 blue 2 green 1
This program should keep asking for an age until it is between 16 and 99. Explain the two defects and write a corrected version.
age = int(input("Age: "))
while age < 16 or age > 99:
print("Age must be 16 to 99")
print("Accepted")
- The loop never asks again, so an invalid age prints the message forever: an infinite loop (logic) (1). Ask for the age inside the loop (1).
- Typing a word such as
tencrashesint()with a ValueError (runtime) (1). Check the input is a whole number before converting it, e.g. withisdigit()ortry/except(1).
while True:
entry = input("Age: ")
if not entry.isdigit():
print("Enter a whole number")
elif not 16 <= int(entry) <= 99:
print("Age must be 16 to 99")
else:
break
print("Accepted:", entry)
Age: ten Enter a whole number Age: 12 Age must be 16 to 99 Age: 17 Accepted: 17
★ A METHOD FOR FIXING DEFECTS
- Read what the code is meant to do, then run it.
- If it crashes, read the error: the last line gives the type, the line number shows where.
- If it runs but the answer is wrong, trace it with a trace table or add print statements.
- Fix one defect at a time and re-run after each fix.
- Test with valid, boundary, invalid and erroneous data (2.12), and record what you changed and why.
Writing a reflective evaluation
An evaluation judges how well your solution meets the brief and what you'd do differently. Like an 'evaluate' exam question, it needs evidence, both strengths and weaknesses, and a supported judgement.
| Cover | Questions to answer |
|---|---|
| Meeting the requirements | Go through the brief. Which requirements does your solution meet fully, partly or not at all? Use your test results as evidence. |
| Quality of the solution | Use the criteria from 2.9.7: efficiency, data structures and types, variables and constants, presentation, maintainability, robustness. |
| Users | Is it usable and accessible for the users in the scenario? (3.1.3) |
| Legal and security | Does it handle personal data properly and protect it? (4.1.3, CA8) |
| Your process | How did your planning and testing go? What would you do differently next time? |
| Improvements | What would you add or change with more time, and why would it help the client? |
◆ SUPPORT: SENTENCE STARTERS
- The solution meets the requirement to ... because test ... showed ...
- A limitation is that ... which means the client ...
- I chose a dictionary for ... because ... However, ...
- If I had more time, I would ... so that ...
- Next time I would plan ... earlier, because ...
- Overall, the solution is ... because ... outweighs ...
✗ COMMON MISTAKES
- Describing what you did instead of judging how well it works.
- Only listing strengths. A balanced evaluation earns more.
- Claims with no evidence. Point to a test, a requirement or a feature.
- Improvements with no reason. Say why each one would help the client or users.