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

Add new config types, improve existing types #2010

Merged
merged 2 commits into from
Jan 31, 2022

Conversation

djmattyg007
Copy link
Contributor

@djmattyg007 djmattyg007 commented Aug 14, 2021

  • Added new Float type. It's very similar to the existing Integer type,
    but accepts floating point numbers, and doesn't allow you to set
    choices.
  • Added new Pair type, for when you want to accept a pair of values in a
    single config setting. Pairs default to a pair of strings, but you can
    set either subtype to whatever type you want (including nested pairs).
  • Added transformer property to String type. This allows you to apply an
    arbitrary transformation to individual config settings that could
    utimately be anything at all.
  • If a transformation is applied to a String config value, it will now
    return a subclass of the built-in str type. This subclass stores the
    original value as well as the transformed value, so that it can be
    re-serialised correctly.
  • The "Expected Path" type originally created for the Path type is (for
    now) just a subclass of the "Transformed Value" class, due to the
    duplicate implementation. In future, this should be updated to return
    pathlib Path objects, not strings.
  • Made Secret type pass through the transformer property correctly to
    its String parent class.
  • Lists can now return a frozenset instead of a tuple, configured by the
    "unique" property.
  • Lists now accept an arbitrary subtype, similar to the Pair type. This
    can be any type at all, including Pairs.
  • Resolved a couple of todo comments regarding missing tests for the
    List type.
  • The Path type will now correctly serialise None to an empty string.

@djmattyg007
Copy link
Contributor Author

This is based on ideas originally described in #1965 and #1966. Follow-up PRs to actually update the file and http extensions will be created once this PR is merged, to avoid this PR becoming any bigger than it already is.

@djmattyg007 djmattyg007 force-pushed the config_handling_improvements branch 2 times, most recently from 63f6da2 to 007a582 Compare August 14, 2021 06:16
@djmattyg007
Copy link
Contributor Author

Here are commits for the HTTP and File extensions, demonstrating how the changes in this commit would be used internally.

f10c93d
f61587c

@kingosticks kingosticks added A-config Area: Config management C-enhancement Category: A PR with an enhancement or an issue with an enhancement proposal labels Jan 26, 2022
Copy link
Member

@jodal jodal left a comment

Choose a reason for hiding this comment

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

Wow, that was quite a lot to review, but it looks solid. 🙌

This leaves me wondering if there isn't some other format (like TOML) or library (like Pydantic) we could use instead of rolling our own config subsystem. I realize that would be a breaking change and not the most productive thing to spend our spare time on, so I'll settle with a solid test suite :-)

mopidy/config/types.py Outdated Show resolved Hide resolved
mopidy/config/types.py Outdated Show resolved Hide resolved
mopidy/config/types.py Show resolved Hide resolved
tests/config/test_types.py Outdated Show resolved Hide resolved
@djmattyg007 djmattyg007 force-pushed the config_handling_improvements branch 4 times, most recently from 9f93b26 to feb53cd Compare January 27, 2022 11:23
@djmattyg007
Copy link
Contributor Author

This leaves me wondering if there isn't some other format (like TOML) or library (like Pydantic) we could use instead of rolling our own config subsystem. I realize that would be a breaking change and not the most productive thing to spend our spare time on, so I'll settle with a solid test suite :-)

The thought had definitely occurred to me too, but yeah, it's obviously a significant amount of work and BC breakage.

For the record, I'd be strongly opposed to implementing Pydantic. I'm not a fan of how it requires your domain models to inherit from their base classes, and all the potential problems that can bring.

While I'm not wedded to it, I've had a lot of success with marshmallow for serialisation+deserialisation, and plain old dataclasses from the stdlib for the domain models. In fact, I've even considered whether it would be worth swapping out the existing models implementation for this paradigm. In python 3.10, dataclasses support automatically generating __slots__, so you can get the benefit of better memory usage (as well as the long-standing built-in support for immutability) while still avoiding boilerplate.

@jodal
Copy link
Member

jodal commented Jan 30, 2022

I've done the rounds through attrs, dataclasses, and Pydantic, and have been quite happy with all of them. I'd use dataclasses for any library that doesn't strictly need more. dataclasses with slots and immutability sounds like a good fit for Mopidy's models, but that still leaves the validation part to us.

@kingosticks
Copy link
Member

I had a random look at some projects in this space yesterday but never used any of them (Mopidy is still my only Python project!). Maybe we should start a new issue/discussion about this topic. Currently I'm not convinced any switch is worth it, we'd always end up having to write extra validators anyway.

@jodal
Copy link
Member

jodal commented Jan 30, 2022

That discussion is clearly too long-term to block this PR. Do you want to give this a review before we merge, @kingosticks ?

subtype.deserialize(v.strip()) for v in values if v.strip()
)
if self._unique:
values = frozenset(values_iter)
Copy link
Member

Choose a reason for hiding this comment

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

This may return a different order compared to the value. I think that would be unexpected.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How much of a concern is it likely to be? The behaviour is opt-in, so I guess we can always adjust the behaviour later based on feedback if absolutely necessary.

Copy link
Member

Choose a reason for hiding this comment

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

If it was documented it'd be better. I just don't like the surprise.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've added a comment 👍

@kingosticks
Copy link
Member

If you rebase you'll pick up the flake8 fix

- Added new Float type. It's very similar to the existing Integer type,
  but accepts floating point numbers, and doesn't allow you to set
  choices.
- Added new Pair type, for when you want to accept a pair of values in a
  single config setting. Pairs default to a pair of strings, but you can
  set either subtype to whatever type you want (including nested pairs).
- Added transformer property to String type. This allows you to apply an
  arbitrary transformation to individual config settings that could
  utimately be anything at all.
- If a transformation is applied to a String config value, it will now
  return a subclass of the built-in str type. This subclass stores the
  original value as well as the transformed value, so that it can be
  re-serialised correctly.
- The "Expected Path" type originally created for the Path type is (for
  now) just a subclass of the "Transformed Value" class, due to the
  duplicate implementation. In future, this should be updated to return
  pathlib Path objects, not strings.
- Made Secret type pass through the transformer property correctly to
  its String parent class.
- Lists can now return a frozenset instead of a tuple, configured by the
  "unique" property.
- Lists now accept an arbitrary subtype, similar to the Pair type. This
  can be any type at all, including Pairs.
- Resolved a couple of todo comments regarding missing tests for the
  List type.
- The Path type will now correctly serialise None to an empty string.
@djmattyg007
Copy link
Contributor Author

I've rebased the branch and added a changelog entry 👍

@kingosticks kingosticks merged commit 3ecbc98 into develop Jan 31, 2022
@kingosticks kingosticks deleted the config_handling_improvements branch January 31, 2022 23:32
@kingosticks kingosticks added this to the Next feature release milestone Jan 31, 2022
@jodal jodal modified the milestones: v3.4.0, v3.3.0 Oct 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-config Area: Config management C-enhancement Category: A PR with an enhancement or an issue with an enhancement proposal
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants