Skip to content

Throw meaningful exceptions in run()#121

Closed
Copilot wants to merge 2 commits intodevelopmentfrom
copilot/throw-meaningful-exceptions
Closed

Throw meaningful exceptions in run()#121
Copilot wants to merge 2 commits intodevelopmentfrom
copilot/throw-meaningful-exceptions

Conversation

Copy link
Copy Markdown

Copilot AI commented Apr 8, 2026

Task

Closes #[issue] — bare exceptions from detect()/parse()/run() propagated to the service as a generic Exception, making it impossible to distinguish library errors from unrelated failures.

Description

Introduces a typed exception hierarchy and wraps all unhandled exceptions raised inside component lifecycle methods so callers can catch and handle them with context.

New src/detectmatelibrary/exceptions.py:

Exception
└── DetectMateError            # base for all library errors
    └── ComponentRunError      # error escaping any component's run()
        ├── DetectorRunError   # error escaping detect()
        └── ParserRunError     # error escaping parse()

All exceptions are exported from detectmatelibrary and detectmatelibrary.common.

Wrapping points:

  • CoreDetector.run() — wraps self.detect()DetectorRunError
  • CoreParser.run() — wraps self.parse()ParserRunError
  • CoreComponent.process() — wraps self.run()ComponentRunError for anything not already a DetectMateError (preserves the specific subclass from the inner layers)

Every wrapped exception carries the original as __cause__ (full traceback preserved) and embeds the component name in the message.

Service-side usage:

try:
    out = self.processor.process(raw)
except DetectorRunError as e:
    logger.error(f"Detector misconfiguration in '{e}': caused by {e.__cause__}")
except ParserRunError as e:
    logger.error(f"Parser failed: {e}")
except ComponentRunError as e:
    logger.error(f"Component error: {e}")

test_bad_players.py updated: test_get_incorrect_schema now expects ComponentRunError (with FieldNotFound as __cause__) — this reflects the intentional new behaviour where schema-layer errors are also surfaced as typed library exceptions.

How Has This Been Tested?

17 new tests in tests/test_common/test_exceptions.py covering:

  • Exception hierarchy (issubclass assertions)
  • ComponentRunError, DetectorRunError, ParserRunError wrapping via process()
  • __cause__ preservation of the original exception
  • Component name present in the exception message
  • Each specific type catchable as its base classes (ComponentRunError, DetectMateError)

Full suite (347 tests) passes.

Checklist

  • This Pull-Request goes to the development branch.
  • I have successfully run prek locally.
  • I have added tests to cover my changes.
  • I have linked the issue-id to the task-description.
  • I have performed a self-review of my own code.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • openaipublic.blob.core.windows.net
    • Triggering command: /usr/bin/python3 python3 -m pytest -q (dns block)
    • Triggering command: /usr/bin/python3 python3 -m pytest -q 3c49�� (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI linked an issue Apr 8, 2026 that may be closed by this pull request
@viktorbeck98 viktorbeck98 requested review from Copilot and ipmach and removed request for Copilot April 8, 2026 08:31
@viktorbeck98
Copy link
Copy Markdown
Collaborator

@ipmach what do you think?

Copilot AI changed the title [WIP] Throw meaningful exceptions in run method Throw meaningful exceptions in run() Apr 8, 2026
Copilot AI requested a review from viktorbeck98 April 8, 2026 08:32
@ipmach ipmach deleted the copilot/throw-meaningful-exceptions branch April 21, 2026 11:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Throw meaningful exceptions in run()

2 participants