Skip to content

wayde22/Price_Compare

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Price Compare

Price Compare is a Python CLI application for comparing product prices across multiple stores with a modular architecture designed for future API-backed and scraping-backed integrations.

The current implementation supports Walmart, Kroger, Home Depot, and Menards through store-specific adapters. Kroger and Walmart can now run in optional live API modes when credentials are configured; Home Depot and Menards currently use local structured catalogs. Results are normalized into a shared schema, matched across stores, stored in SQLite for price history, and surfaced through a CLI that supports exports, watchlists, history lookups, and scheduled reruns.

Features

  • Modular adapter architecture with one adapter per store
  • Shared normalized product schema using Pydantic models
  • Matching and comparison engine with cheapest-item detection
  • SQLite-backed persistence for searches, products, snapshots, comparison runs, and watchlists
  • CLI support for search, watchlist, history, and scheduled run modes
  • JSON and CSV export options
  • Configurable timeout, retries, rate limiting, enabled stores, database path, default ZIP code, log level, user agent, and live API settings for Kroger and Walmart
  • Unit and mocked adapter tests with no live HTTP calls

Requirements

  • Python 3.14
  • pip

Installation

pip install -e .[dev]

Configuration

Copy config/settings.toml.example to config/settings.toml and adjust values as needed.

Example settings:

request_timeout = 10.0
retry_count = 3
rate_limit_delay = 0.5
log_level = "INFO"
user_agent = "price-compare/0.1.0"
enabled_stores = ["walmart", "kroger", "home_depot", "menards"]
database_path = "data/price_compare_storage.sqlite3"
default_zip_code = "60601"
use_live_kroger_api = false
kroger_api_base_url = "https://api.kroger.com/v1"
kroger_client_id = ""
kroger_client_secret = ""
kroger_scope = "product.compact"
kroger_search_limit = 10
use_live_walmart_api = false
walmart_api_base_url = "https://marketplace.walmartapis.com/v3"
walmart_client_id = ""
walmart_client_secret = ""
walmart_search_limit = 10

Environment variable overrides are also supported for the live Kroger and Walmart integrations:

USE_LIVE_KROGER_API=true
KROGER_CLIENT_ID=your-client-id
KROGER_CLIENT_SECRET=your-client-secret
KROGER_SCOPE=product.compact
USE_LIVE_WALMART_API=true
WALMART_CLIENT_ID=your-client-id
WALMART_CLIENT_SECRET=your-client-secret
WALMART_API_BASE_URL=https://marketplace.walmartapis.com/v3
PRICE_COMPARE_USER_AGENT=price-compare/0.1.0

Live Kroger API Setup

To use live Kroger product data instead of the local sample catalog, create a Kroger developer application and configure credentials in config/settings.toml or environment variables.

Suggested settings:

use_live_kroger_api = true
kroger_api_base_url = "https://api.kroger.com/v1"
kroger_client_id = "your-client-id"
kroger_client_secret = "your-client-secret"
kroger_scope = "product.compact"

Once enabled, Kroger searches use the live API and pass the ZIP code through as a location hint. If live mode is enabled without credentials, the adapter logs a warning and falls back to the local sample catalog.

Live Walmart API Setup

To use live Walmart product data instead of the local sample catalog, configure your Walmart Marketplace credentials in config/settings.toml or environment variables.

Suggested settings:

use_live_walmart_api = true
walmart_api_base_url = "https://marketplace.walmartapis.com/v3"
walmart_client_id = "your-client-id"
walmart_client_secret = "your-client-secret"
walmart_search_limit = 10

Once enabled, Walmart searches use the live marketplace catalog search API. If live mode is enabled without credentials, the adapter logs a warning and falls back to the local sample catalog.

How To Run

Run the CLI from the project root:

python main.py

Available CLI flows:

  • search: compare products across enabled stores
  • watchlist: list saved watchlist queries and optionally rerun them
  • history: show historical prices for a product name
  • schedule: manually trigger a scheduled-style rerun of saved watchlist entries
  • kroger-check: verify live Kroger API credentials and a ZIP-based search
  • walmart-check: verify live Walmart API credentials and a query-based search

How To Use The App

When you start the app, it prompts for an action:

Choose action [search/watchlist/history/schedule/kroger-check/walmart-check] (default search):

Search flow

Use search to compare current results across enabled stores.

Typical prompts:

Enter product search query:
Enter ZIP code [60601]:
Export results? [none/json/csv/both]:
Save this query to watchlist? [y/N]:
Optional alert threshold price (press Enter to skip):

Example:

Choose action [search/watchlist/history/schedule/kroger-check/walmart-check] (default search): search
Enter product search query: paper towels
Enter ZIP code [60601]: 60601
Export results? [none/json/csv/both]: json
Save this query to watchlist? [y/N]: y
Optional alert threshold price (press Enter to skip): 9.50

What happens:

  • The app runs enabled store adapters.
  • Kroger uses the live API when use_live_kroger_api = true and credentials are configured.
  • Walmart uses the live API when use_live_walmart_api = true and credentials are configured.
  • Products are normalized and matched across stores.
  • The CLI prints grouped comparison results and highlights the cheapest item.
  • If you export, files are written to exports/.
  • If you save the query, it is stored in SQLite for later watchlist and alert checks.

Full example session:

$ python main.py
Choose action [search/watchlist/history/schedule/kroger-check/walmart-check] (default search): search
Enter product search query: paper towels
Enter ZIP code [60601]: 60601

Price comparison results
------------------------
Query: paper towels
ZIP code: 60601
Stores enabled: walmart, kroger, home_depot, menards

Group 1: group-1
Confidence: exact
Price difference: $1.50
store   | product name                      | price  | unit price | confidence | cheapest
--------+-----------------------------------+--------+------------+------------+---------
walmart | Bounty Select-A-Size Paper Towels | $12.49 | $1.56      | exact      |
kroger  | Bounty Select-A-Size Paper Towels | $10.99 | $1.37      | exact      | YES
menards | Bounty Select-A-Size Paper Towels | $10.99 | $1.37      | exact      |

Cheapest item: kroger | Bounty Select-A-Size Paper Towels | $10.99
Lowest saved price: kroger | Bounty Select-A-Size Paper Towels | $10.99
Last known prices by store:
  - walmart: $12.49
  - kroger: $10.99
  - menards: $10.99
Price changes since last run:
  - walmart: $12.49 -> $12.49 (change $0.00)
  - kroger: $10.99 -> $10.99 (change $0.00)
  - menards: $10.99 -> $10.99 (change $0.00)
Export results? [none/json/csv/both]: json
Exported JSON: exports/paper_towels_60601.json
Save this query to watchlist? [y/N]: y
Optional alert threshold price (press Enter to skip): 9.50
Saved to watchlist.

In that example, the person:

  • chooses search at the first prompt
  • enters a product query and ZIP code
  • reviews the comparison output
  • exports the results as JSON
  • saves the query to the watchlist
  • sets an alert threshold for later checks

Watchlist flow

Use watchlist to review saved queries and optionally rerun them immediately.

Example:

Choose action [search/watchlist/history/schedule/kroger-check/walmart-check] (default search): watchlist
Re-run all watchlist queries now? [y/N]: y

Example interaction:

$ python main.py
Choose action [search/watchlist/history/schedule/kroger-check/walmart-check] (default search): watchlist

Watchlist
---------
1. paper towels (60601)
2. drill (60601)
Re-run all watchlist queries now? [y/N]: y

This mode is useful when you want to check tracked items without retyping each search.

History flow

Use history to inspect saved pricing data for a product name that has already been captured in earlier runs.

Example:

Choose action [search/watchlist/history/schedule/kroger-check/walmart-check] (default search): history
Enter product name for history: Bounty Select-A-Size Paper Towels

Example interaction:

$ python main.py
Choose action [search/watchlist/history/schedule/kroger-check/walmart-check] (default search): history
Enter product name for history: Bounty Select-A-Size Paper Towels

Price history
-------------
Historical lowest: kroger | Bounty Select-A-Size Paper Towels | $10.99
Last known prices by store:
  - walmart: $12.49
  - kroger: $10.99
  - menards: $10.99
Recorded price history:
  - 2026-04-18T01:59:40.245752+00:00 | walmart | $12.49 | Bounty Select-A-Size Paper Towels
  - 2026-04-18T01:59:40.246676+00:00 | kroger | $10.99 | Bounty Select-A-Size Paper Towels
  - 2026-04-18T01:59:40.248020+00:00 | menards | $10.99 | Bounty Select-A-Size Paper Towels

This mode shows:

  • historical lowest saved price
  • last known price by store
  • recorded price history entries over time

Schedule flow

Use schedule to manually trigger a batch-style rerun of all saved watchlist entries.

Example:

Choose action [search/watchlist/history/schedule/kroger-check/walmart-check] (default search): schedule

Example interaction:

$ python main.py
Choose action [search/watchlist/history/schedule/kroger-check/walmart-check] (default search): schedule

Scheduled run starting...

This mode behaves like a simple scheduled execution pass and prints fresh comparison output for each saved watchlist query.

Kroger connectivity check

Use kroger-check to verify that live Kroger API mode is configured correctly before relying on it in the full comparison flow.

Example interaction:

$ python main.py
Choose action [search/watchlist/history/schedule/kroger-check/walmart-check] (default search): kroger-check

Kroger live connectivity check
-----------------------------
Config summary:
  - live API enabled: yes
  - API base URL: https://api.kroger.com/v1
  - scope: product.compact
  - search limit: 10
  - client ID configured: yes
  - client secret configured: yes
  - default ZIP code: 60601
Enter Kroger test query [milk]: milk
Enter ZIP code [60601]: 62959
Connection successful. Retrieved 3 raw result(s).
Sample normalized results:
store  | product name                    | price | unit price | confidence | cheapest
-------+---------------------------------+-------+------------+------------+---------
kroger | Simple Truth Organic Whole Milk | $3.99 | $0.07      | n/a        | YES

If live Kroger mode is disabled or credentials are missing, the CLI explains that directly instead of running the check. It also prints a safe config summary so you can quickly see whether the live mode flag, base URL, scope, and credential presence are set correctly without exposing the secret value.

Walmart connectivity check

Use walmart-check to verify that live Walmart API mode is configured correctly before relying on it in the full comparison flow.

Example interaction:

$ python main.py
Choose action [search/watchlist/history/schedule/kroger-check/walmart-check] (default search): walmart-check

Walmart live connectivity check
------------------------------
Config summary:
  - live API enabled: yes
  - API base URL: https://marketplace.walmartapis.com/v3
  - search limit: 10
  - client ID configured: yes
  - client secret configured: yes
  - default ZIP code: 60601
Enter Walmart test query [milk]: milk
Enter ZIP code [60601]: 62959
Connection successful. Retrieved 2 raw result(s).
Sample normalized results:
store   | product name           | price | unit price | confidence | cheapest
--------+------------------------+-------+------------+------------+---------
walmart | Great Value Whole Milk | $3.78 | n/a        | n/a        | YES

If live Walmart mode is disabled or credentials are missing, the CLI explains that directly and shows a safe config summary without exposing the secret value.

Notes on matching and history

  • Price history is built from saved comparison runs in the local SQLite database.
  • History lookups work best when you search using consistent product terms over time.
  • Matching uses identifiers, brand and size checks, and fuzzy title similarity to avoid bad comparisons.

PyCharm entry point:

  • Script path: main.py
  • Working directory: D:\Dev\Python_Projects\Price_Compare

How To Test

Run the full test suite:

python -m pytest

The suite covers:

  • normalization and model validation
  • matching and comparison logic
  • repository and history behavior
  • adapter parsing with mocked/local inputs only
  • HTTP and parser failure handling
  • logging configuration and adapter debug traces

Architecture Overview

Project layout:

  • app/cli.py: CLI entry flow and user-facing output
  • app/core/: configuration, logging, and shared exceptions
  • app/models/: shared domain models and comparison result structures
  • app/adapters/: one adapter per store plus registry and local catalog helpers
  • app/services/: matching and comparison orchestration
  • app/storage/: SQLite initialization and repository access
  • app/utils/: HTTP, parsing, retry, and matching utilities
  • tests/: unit and adapter test suite

Comparison flow:

  1. The CLI gathers the search query and location.
  2. The adapter registry runs enabled store adapters and normalizes results.
  3. The matching service groups likely-equivalent products across stores.
  4. The comparison service identifies the cheapest option, computes price changes, and checks alerts.
  5. The repository persists results for later history and watchlist use.

Notes

  • Kroger and Walmart support optional live API paths; Home Depot and Menards are still local-data adapters for now.
  • The adapter and HTTP layers are intentionally separated so live APIs or scrapers can replace the local data sources later without rewriting the comparison logic.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages