Skip to content

fix: raise NotImplementedError and avoid mutable default args#6363

Open
Mr-Neutr0n wants to merge 3 commits intoespnet:masterfrom
Mr-Neutr0n:fix/return-notimplemented-and-mutable-defaults
Open

fix: raise NotImplementedError and avoid mutable default args#6363
Mr-Neutr0n wants to merge 3 commits intoespnet:masterfrom
Mr-Neutr0n:fix/return-notimplemented-and-mutable-defaults

Conversation

@Mr-Neutr0n
Copy link
Copy Markdown

Summary

  • Fix return NotImplementedError -> raise NotImplementedError in 5 abstract base classes. Using return silently returns the exception class object as a value instead of raising it, so subclasses that forget to override the name property would not get an error at runtime.

    Affected files:

    • espnet2/s2st/losses/abs_loss.py
    • espnet2/s2st/aux_attention/abs_aux_attention.py
    • espnet2/enh/loss/criterions/abs_loss.py
    • espnet2/asvspoof/loss/abs_loss.py
    • espnet2/uasr/loss/abs_loss.py
  • Fix mutable default argument others={} -> others=None with a None guard in 4 enhancement loss wrapper forward() methods. Mutable default arguments in Python are shared across all calls, which can lead to subtle bugs if the dict is ever mutated.

    Affected files:

    • espnet2/enh/loss/wrappers/pit_solver.py
    • espnet2/enh/loss/wrappers/dpcl_solver.py
    • espnet2/enh/loss/wrappers/multilayer_pit_solver.py
    • espnet2/enh/loss/wrappers/fixed_order.py

Test plan

  • All changes are minimal and behavior-preserving for correct usage
  • Existing unit tests pass (pytest test/espnet2/enh/loss/)
  • No new dependencies introduced

…table default arguments

In several abstract base classes, `return NotImplementedError` was used
instead of `raise NotImplementedError`, which silently returns the
exception class as a value rather than raising it. This means subclasses
that forget to override the `name` property would not get an error.

Also replace mutable default argument `others={}` with `others=None`
in enhancement loss wrapper forward() methods to avoid the well-known
Python mutable default argument pitfall.

Affected files:
- espnet2/s2st/losses/abs_loss.py
- espnet2/s2st/aux_attention/abs_aux_attention.py
- espnet2/enh/loss/criterions/abs_loss.py
- espnet2/asvspoof/loss/abs_loss.py
- espnet2/uasr/loss/abs_loss.py
- espnet2/enh/loss/wrappers/pit_solver.py
- espnet2/enh/loss/wrappers/dpcl_solver.py
- espnet2/enh/loss/wrappers/multilayer_pit_solver.py
- espnet2/enh/loss/wrappers/fixed_order.py
@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. Bugfix labels Feb 11, 2026
@mergify mergify Bot added the ESPnet2 label Feb 11, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request correctly addresses two important issues: replacing return NotImplementedError with raise NotImplementedError in abstract base classes to ensure proper error handling, and fixing the use of mutable default arguments, which is a common source of bugs in Python.

The changes are well-implemented. However, the fix for mutable default arguments in the wrapper classes highlights a pre-existing issue with method signature mismatches between these classes and their AbsLossWrapper base class. The forward method in the subclasses has a signature that is incompatible with the one defined in the abstract base class, violating the Liskov Substitution Principle. I've added comments with high severity to these files, recommending that the base class be updated to ensure type consistency and maintainability across the codebase.

self.weight = weight

def forward(self, ref, inf, others={}):
def forward(self, ref, inf, others=None):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

While changing the mutable default argument is correct, this method's signature is incompatible with the base class AbsLossWrapper. The base class defines forward(self, ..., others: Dict), making others a required argument. This implementation makes it optional (others=None). This violates the Liskov Substitution Principle and can cause issues with static analysis tools. To fix this properly, the base class AbsLossWrapper should be updated to def forward(self, ..., others: Optional[Dict] = None) to reflect that others is optional. This should be addressed to ensure type consistency.

self.weight = weight

def forward(self, ref, inf, others={}):
def forward(self, ref, inf, others=None):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This change to avoid a mutable default argument is good, but it reveals a signature mismatch with the base class AbsLossWrapper. The base class expects others as a required Dict argument, but here it is optional (others=None). This violates the Liskov Substitution Principle. For type safety, the signature in the subclass should be compatible with the superclass. Consider updating the base class AbsLossWrapper to define others as optional: others: Optional[Dict] = None.

self.layer_weights = layer_weights

def forward(self, ref, infs, others={}):
def forward(self, ref, infs, others=None):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

While fixing the mutable default argument is correct, this method signature has a more fundamental incompatibility with the base class AbsLossWrapper. The base class signature is forward(self, ref: List, inf: List, others: Dict). This implementation's signature is forward(self, ref, infs, others=None).

There are two inconsistencies:

  1. The second argument is infs instead of inf, with a different type.
  2. others is made optional, while it's required in the base class.

This violates the Liskov Substitution Principle. The inheritance relationship should be reviewed. If MultiLayerPITSolver should conform to the AbsLossWrapper interface, its forward method signature must be compatible. This might require refactoring the base class or the inheritance structure.

self.flexible_numspk = flexible_numspk

def forward(self, ref, inf, others={}):
def forward(self, ref, inf, others=None):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Fixing the mutable default argument is a good improvement. However, this change makes the method signature incompatible with the AbsLossWrapper base class. The base class specifies others: Dict as a required argument, while this implementation makes it optional. This violates the Liskov Substitution Principle. The base class AbsLossWrapper should ideally be changed to ... others: Optional[Dict] = None to make the contract clear and consistent across subclasses.

@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 17, 2026

Codecov Report

❌ Patch coverage is 91.66667% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 69.63%. Comparing base (321cebd) to head (7d49a81).
⚠️ Report is 519 commits behind head on master.

Files with missing lines Patch % Lines
espnet2/enh/loss/wrappers/dpcl_solver.py 66.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6363      +/-   ##
==========================================
+ Coverage   69.53%   69.63%   +0.10%     
==========================================
  Files         774      775       +1     
  Lines       70978    71545     +567     
==========================================
+ Hits        49352    49820     +468     
- Misses      21626    21725      +99     
Flag Coverage Δ
test_integration_espnet2 46.88% <41.66%> (-0.01%) ⬇️
test_python_espnet2 61.05% <91.66%> (-0.48%) ⬇️
test_python_espnet3 17.13% <33.33%> (+0.51%) ⬆️
test_utils 61.05% <91.66%> (-0.48%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Fhrozen Fhrozen added this to the v.202601 milestone Feb 22, 2026
@Fhrozen Fhrozen modified the milestones: v.202604, v.202607 Apr 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bugfix ESPnet2 size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants