Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow discard_init_args_on_class_path_change to handle more nested contexts #248

Merged
merged 3 commits into from
Mar 9, 2023

Conversation

speediedan
Copy link
Contributor

What does this PR do?

Fixes #247

While a subclass_spec can be either a dict or Namespace

def is_subclass_spec(val):
is_class = isinstance(val, (dict, Namespace)) and 'class_path' in val
if is_class:
keys = getattr(val, '__dict__', val).keys()
is_class = len(set(keys)-{'class_path', 'init_args', 'dict_kwargs', '__path__'}) == 0
return is_class

when entering ActionTypeHint.discard_init_args_on_class_path_change:
@staticmethod
def discard_init_args_on_class_path_change(parser_or_action, prev_cfg, cfg):
if isinstance(prev_cfg, dict):
return
keys = list(prev_cfg.keys(branches=True))
num = 0
while num < len(keys):
key = keys[num]
prev_val = prev_cfg.get(key)
val = cfg.get(key)
if is_subclass_spec(prev_val) and is_subclass_spec(val):
action = parser_or_action
if not isinstance(parser_or_action, ActionTypeHint):
action = _find_action(parser_or_action, key)
if isinstance(action, ActionTypeHint):
discard_init_args_on_class_path_change(action, prev_val, val)

jsonargparse.typehints.discard_init_args_on_class_path_change below currently assumes any previous value for a nested subclass will already have been cast as a Namespace:

def discard_init_args_on_class_path_change(parser_or_action, prev_val, value):
if prev_val and 'init_args' in prev_val and prev_val['class_path'] != value['class_path']:
parser = parser_or_action
if isinstance(parser_or_action, ActionTypeHint):
sub_add_kwargs = getattr(parser_or_action, 'sub_add_kwargs', {})
parser = ActionTypeHint.get_class_parser(value['class_path'], sub_add_kwargs)
del_args = {}
for key, val in list(prev_val.init_args.__dict__.items()):
action = _find_action(parser, key)

with L941 resulting in:

argparse.ArgumentError: Parser key "some_class":
  Problem with given class_path '__main__.CustomModule':
    - 'dict' object has no attribute 'init_args'

Right now, nested generic dict configurations like the repro case I include below don't trigger the subclass_spec_as_namespace Namespace wrapping that jsonargparse.typehints.discard_init_args_on_class_path_change requires when removing overridden subclass spec configuration in this context.

With this PR's minor patch to jsonargparse.typehints.discard_init_args_on_class_path_change, this use case can be accommodated. This PR also adds a test that covers the expanded support.

## Before submitting

- [x] Did you read the [contributing guideline](https://github.com/omni-us/jsonargparse/blob/master/CONTRIBUTING.rst)?
- [x] Did you update **the documentation**? (readme and public docstrings)
- [x] Did you write **unit tests** such that there is 100% coverage on related code? (required for bug fixes and new features)
- [x] Did you verify that new and existing **tests pass locally**?
- [x] Did you make sure that all changes preserve **backward compatibility**?
- [x] Did you update **the CHANGELOG**? (not for typos, docs, test updates, or minor internal changes/refactors)

@speediedan speediedan marked this pull request as ready for review February 23, 2023 06:11
Copy link
Member

@mauvilsa mauvilsa left a comment

Choose a reason for hiding this comment

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

Sorry for not looking at this sooner. Thank you very much for contributing!

Please add an entry to the changelog.

jsonargparse/typehints.py Outdated Show resolved Hide resolved
@mauvilsa mauvilsa added the bug Something isn't working label Mar 7, 2023
@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 9, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
0.0% 0.0% Duplication

@codecov-commenter
Copy link

Codecov Report

Patch coverage: 100.00% and no project coverage change

Comparison is base (14b4842) 100.00% compared to head (cb2d122) 100.00%.

📣 This organization is not using Codecov’s GitHub App Integration. We recommend you install it so Codecov can continue to function properly for your repositories. Learn more

Additional details and impacted files
@@            Coverage Diff            @@
##            master      #248   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           20        20           
  Lines         5189      5190    +1     
=========================================
+ Hits          5189      5190    +1     
Flag Coverage Δ
py3.10 87.93% <100.00%> (+<0.01%) ⬆️
py3.10_all 99.88% <100.00%> (+<0.01%) ⬆️
py3.6 87.57% <100.00%> (+<0.01%) ⬆️
py3.6_all 99.63% <100.00%> (+<0.01%) ⬆️
py3.7 87.59% <100.00%> (+<0.01%) ⬆️
py3.7_all 99.80% <100.00%> (+<0.01%) ⬆️
py3.8 87.91% <100.00%> (+<0.01%) ⬆️
py3.8_all 99.84% <100.00%> (+<0.01%) ⬆️
py3.9 87.91% <100.00%> (+<0.01%) ⬆️
py3.9_all 99.86% <100.00%> (+<0.01%) ⬆️

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

Impacted Files Coverage Δ
jsonargparse/typehints.py 100.00% <100.00%> (ø)

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

@mauvilsa mauvilsa merged commit 1fce989 into omni-us:master Mar 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

discard_init_args_on_class_path_change does not handle nested dict subclass specs in some contexts
3 participants