feat: Allow IDs or Models to be passed to all publishing APIs#564
feat: Allow IDs or Models to be passed to all publishing APIs#564kdmccormick wants to merge 3 commits intomainfrom
Conversation
| if isinstance(learning_package_id, LearningPackage): | ||
| return learning_package_id |
There was a problem hiding this comment.
Yes, I know this is funny :P But it makes the rest of the code simpler.
497859c to
1a96f07
Compare
| created_by: int | None, | ||
| *, | ||
| dependencies: list[int] | None = None, # PublishableEntity IDs | ||
| dependencies: Sequence[PublishableEntity.ID] | None = None, |
There was a problem hiding this comment.
list is invariant (its items must be the exact type, not subclasses thereof), whereas Sequence is covariant, thus more likely to behave with mypy the way consumers expect.
|
@bradenmacdonald Could you review? If you like it, I'll do the other applets this way too. |
620780c to
f6cb1b7
Compare
1a96f07 to
2be18fa
Compare
|
@kdmccormick I like it! Could you please add a test for the |
f6cb1b7 to
905f820
Compare
2be18fa to
62507c8
Compare
62507c8 to
eb725ab
Compare
These weren't passing mypy, reverting for now
50fff8e to
cb7742e
Compare
|
@kdmccormick I'm curious why get_model_id() wasn't typechecking properly? I tried out your branch before and it seemed to be working fine. |
|
@bradenmacdonald It passes mypy. The issue is that mypy seems to effectively consisder For example. # given:
my_model_or_id: Model | int
# these pass, as we'd expect
my_id: LearningPackage.ID = get_model_id(my_model_or_id)
my_id: int = get_model = get_model_id(my_model_or_id)
# but this passes too :(
my_id: str = get_model_id(my_model_or_id)It seems that mypy doesn't respect You're welcome to take a whack at it--I'm going to put this down to focus on the timestamp & author stuff. |
|
The problem you're encountering is that you're defining models in Lines 12 to 13 in c3d876d So it's not properly typing all the relation and ID accessors on those particular models. I think it's safe to change mypy to use
I think you mean given It seems to be working fine for me on 8dc3240 # tests/openedx_django_lib/test_typing.py
def more_tests(my_model_or_id: LearningPackage | LearningPackage.ID) -> None:
# these pass, as we'd expect
my_typed_id: LearningPackage.ID = get_model_id(my_model_or_id)
my_int_id: int = get_model_id(my_model_or_id)
# but this passes too :(
my_str_id: str = get_model_id(my_model_or_id)
def more_tests2(my_model_or_id: MyTypedModel | MyTypedModel.ID) -> None:
# these pass, as we'd expect
my_typed_id: MyTypedModel.ID = get_model_id(my_model_or_id)
my_int_id: int = get_model_id(my_model_or_id)
# but this passes too :(
my_str_id: str = get_model_id(my_model_or_id)mypy: |
Part of: #562
To reduce noise in the implementations, I'm proposing these general patterns:
model,model_id, ormodel_or_id.model_idand immediately invokemodel_id = get_model_id(model_id).modeland immediately invokemodel = get_<model>(model).If this looks good, I'll apply it to the other applets as well.
BREAKING CHANGE: Some API functions which previously accepted
intnow accept<Model>.ID. Runtime behavior has not changed, but callers may need to use additional annotations ortyping.cast(...)in order to get their typechecker to pass.