Skip to content

About

Debugging and validating a Python sales data workflow

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

Debugging a Sales Data Workflow

Project Overview

This project demonstrates how to troubleshoot a sales-data validation workflow without modifying the original sales.csv file.

The provided load_and_check() function:

  1. Loads sales.csv.
  2. Checks whether the dataset has the expected number of columns.
  3. Calculates date-level statistics for the Total column.
  4. Creates two integrity checks:
    • Condition_1: checks whether Total is within the calculated acceptable range for its date.
    • Condition_2: checks whether Tax equals 5% of Quantity × Unit price.
  5. Reports whether the data passes the integrity checks.

The objective is to fix the issues inside the load_and_check() function only and finish with exactly two success messages:

Data loaded successfully.
Data integrity check was successful!

The raw sales.csv file is not modified.


Initial Problems

When the original function is executed, it produces:

Data column mismatch! Expected 18, but got 17. Columns found: [...]
Data integrity check failed! 0 rows failed Condition_1, 346 rows failed Condition_2.

There are two issues.

1. Incorrect expected column count

The function expects 18 columns:

expected_columns = 18

However, the supplied sales.csv contains 17 columns.

The columns are:

Invoice ID
Branch
City
Customer type
Gender
Product line
Unit price
Quantity
Tax
Total
Date
Time
Payment
cogs
gross margin percentage
gross income
Rating

Therefore, the expected column count in the validation needs to be changed from 18 to 17.

2. Tax fails the integrity check

The original function checks:

round(data['Quantity'] * data['Unit price'] * 0.05, 1) == round(data['Tax'], 1)

The supplied data does not pass this check for all rows.

The task specifically allows columns to be corrected inside the function. Therefore, before Condition_2 is evaluated, Tax is recalculated from the source columns:

data['Tax'] = (data['Quantity'] * data['Unit price']).astype(float) * 0.05

This keeps the raw CSV unchanged while ensuring that the Tax column is consistent with the stated business rule.


Corrected Workflow

The corrected function makes two targeted changes:

Change 1 — Correct the expected number of columns

expected_columns = 17

Change 2 — Recalculate Tax inside the function

data['Tax'] = (data['Quantity'] * data['Unit price']).astype(float) * 0.05

The Tax correction is made after the grouped statistics are merged and before Condition_2 is evaluated.

No manual changes are made to sales.csv.


Final Code

import pandas as pd

def load_and_check():
    # Step 1: Load the data and check if it has the expected shape
    data = pd.read_csv('sales.csv')

    expected_columns = 17
    actual_columns = data.shape[1]

    if actual_columns != expected_columns:
        print(f"Data column mismatch! Expected {expected_columns}, but got {actual_columns}.")
        print(f"Columns found: {list(data.columns)}")
    else:
        print("Data loaded successfully.")

    # Step 2: Calculate statistical values and merge with the original data
    grouped_data = data.groupby(['Date'])['Total'].agg(['mean', 'std'])
    grouped_data['threshold'] = 3 * grouped_data['std']
    grouped_data['max'] = grouped_data['mean'] + grouped_data.threshold
    grouped_data['min'] = grouped_data[['mean', 'threshold']].apply(
        lambda row: max(0, row['mean'] - row['threshold']),
        axis=1
    )

    data = pd.merge(data, grouped_data, on='Date', how='left')

    # Correct Tax inside the function before Condition_2 is checked
    data['Tax'] = (data['Quantity'] * data['Unit price']).astype(float) * 0.05

    # Condition_1 checks if 'Total' is within the acceptable range
    # (min to max) for each date
    data['Condition_1'] = (
        (data['Total'] >= data['min']) &
        (data['Total'] <= data['max'])
    )
    data['Condition_1'].fillna(False, inplace=True)

    # Condition_2 checks whether Tax is 5% of Quantity * Unit price
    data['Condition_2'] = (
        round(data['Quantity'] * data['Unit price'] * 0.05, 1)
        == round(data['Tax'], 1)
    )

    # Step 3: Check if all rows pass both conditions
    failed_condition_1 = data[~data['Condition_1']]
    failed_condition_2 = data[~data['Condition_2']]

    if failed_condition_1.shape[0] > 0 or failed_condition_2.shape[0] > 0:
        print(
            f"Data integrity check failed! "
            f"{failed_condition_1.shape[0]} rows failed Condition_1, "
            f"{failed_condition_2.shape[0]} rows failed Condition_2."
        )
    else:
        print("Data integrity check was successful!")

    return data


processed_data = load_and_check()

Expected Result

With the supplied sales.csv, the corrected workflow should produce the two success messages:

Data loaded successfully.
Data integrity check was successful!

The function returns the processed DataFrame in processed_data.

The raw sales.csv remains unchanged.


Key Debugging Lessons

  • Read the error output before changing the code.
  • Verify assumptions about the input data instead of assuming the expected schema is correct.
  • Use the existing integrity checks to identify where the pipeline is failing.
  • Fix data transformations inside the pipeline when the task requires the raw input to remain unchanged.
  • Recalculate derived fields from their source columns when the business rule is known.
  • Make the smallest targeted changes necessary to restore the workflow.

Files

sales_debugging_workflow/
├── README.md
├── sales_debugging_workflow.ipynb
└── sales.csv

sales.csv should be kept as the original input dataset and should not be manually edited.

About

Debugging and validating a Python sales data workflow

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages