-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a test using dynamic subclasses and bump min python to 3.9
Python 3.8 doesn't have the dict union operator | and you can't make union types using Union[type1, type2] so I bumped the minimum python version to 3.9
- Loading branch information
1 parent
8c1ff18
commit ed0cd57
Showing
3 changed files
with
101 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
from unittest.mock import patch | ||
import pytest | ||
from conflator import CLIArg, Conflator, EnvVar, ConfigModel | ||
from annotated_types import Annotated | ||
from typing import Literal, Union | ||
from pydantic import Field, ConfigDict | ||
import yaml | ||
|
||
from dataclasses import dataclass, field | ||
|
||
class Action(ConfigModel): | ||
model_config = ConfigDict(extra='forbid') | ||
name: str | ||
|
||
class Source(Action): | ||
"Produces messages" | ||
name: Literal["Source"] | ||
start_from: str | ||
|
||
class Process(Action): | ||
"Processes messages" | ||
name: Literal["Process"] | ||
should_flub_widgets: bool | ||
|
||
class Sink(Action): | ||
"Consumes messages" | ||
name: Literal["Sink"] | ||
emit_aviso_notification: bool | ||
|
||
@dataclass | ||
class Subclasses: | ||
"""Get all the subclasses for given class | ||
returns {name : class} | ||
deduplicated by name | ||
cached | ||
""" | ||
|
||
cache: dict = field(default_factory=dict) | ||
|
||
def get(self, target): | ||
try: | ||
return self.cache[target.__name__] | ||
except KeyError: | ||
# Deduplicate classes by __name__ | ||
deduped = list({subcls.__name__: subcls for subcls in target.__subclasses__()}.values()) | ||
subclasses = {target.__name__: target} | {k: v for subcls in deduped for k, v in self.get(subcls).items()} | ||
subclasses[target.__name__] = target | ||
self.cache[target.__name__] = subclasses | ||
return subclasses | ||
|
||
# Get all the subclasses of Action and remove Action itself | ||
action_subclasses = tuple(set(Subclasses().get(Action).values()) - set([Action,])) | ||
|
||
# Constuct a union type out of the subclasses | ||
# Field(discriminator="name") tells pydantic to look at the name | ||
# field to decide what type of the union to attempt to parse | ||
action_subclasses_union = Annotated[ | ||
Union[action_subclasses], | ||
Field(discriminator="name")] | ||
|
||
class Config(ConfigModel): | ||
actions: list[action_subclasses_union] = Field(discriminator='name') | ||
|
||
|
||
def test_subclasses(): | ||
config = yaml.safe_load(""" | ||
actions: | ||
- name: "Source" | ||
start_from: 01031997 | ||
# should_flub_widgets: True # extra key | ||
- name: Process | ||
should_flub_widgets: True | ||
- name: Sink | ||
emit_aviso_notification: False | ||
""") | ||
conflator = Conflator("test-app", Config, cli = False, **config) | ||
config = conflator.load() | ||
|
||
assert config.actions[0].name == "Source" | ||
|
||
|
||
def test_subclasses_extra_key(): | ||
with pytest.raises(SystemExit): | ||
config = yaml.safe_load(""" | ||
actions: | ||
- name: "Source" | ||
start_from: 01031997 | ||
should_flub_widgets: True # extra key | ||
- name: Process | ||
should_flub_widgets: True | ||
- name: Sink | ||
emit_aviso_notification: False | ||
""") | ||
conflator = Conflator("test-app", Config, cli = False, **config) | ||
config = conflator.load() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
[tox] | ||
env_list = py{38,39,310,311} | ||
env_list = py{39,310,311} | ||
minversion = 4.12.1 | ||
|
||
[testenv] | ||
|