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

Issue 6810 type annotations for sqlalchemy.orm.mapped_collection #6

Closed

Conversation

mlatysh
Copy link

@mlatysh mlatysh commented Jan 12, 2023

Description

An attempt to annotate lib/sqlalchemy/orm/mapped_collection.py with type hints (issue sqlalchemy#6810)

Checklist

This pull request is:

  • A documentation / typographical error fix
    • Good to go, no issue or tests are needed
  • A short code fix
    • please include the issue number, and create an issue if none exists, which
      must include a complete example of the issue. one line code fixes without an
      issue and demonstration will not be accepted.
    • Please include: Fixes: #<issue number> in the commit message
    • please include tests. one line code fixes without tests will not be accepted.
  • A new feature implementation
    • please include the issue number, and create an issue if none exists, which must
      include a complete example of how the feature would look.
    • Please include: Fixes: #<issue number> in the commit message
    • please include tests.

Have a nice day!

@mlatysh mlatysh self-assigned this Jan 12, 2023
@g-kisenkov g-kisenkov marked this pull request as ready for review January 17, 2023 09:05
m._get_state_attr_by_column(state, state.dict, col)
for col in self._cols(m)
]
if self.composite:
return tuple(key)
else:
return key[0]
return key[0] # type: ignore

Choose a reason for hiding this comment

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

KeyedColumnElement is actually from sql.elements and its key attribute is of str type - so it might be that the elements in key list here are strings. We probably can't do much more here, since _get_state_attr_by_column() has Mike's annotations - just wanted to add a bit of context from sql.elements.

@mlatysh mlatysh force-pushed the issue_6810_type_annotate_sqlalchemy.orm.mapped_collection branch from 9dc33c3 to d580a92 Compare January 17, 2023 15:05
Copy link

@jazzthief jazzthief left a comment

Choose a reason for hiding this comment

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

Nothing more from my end, good job!

Copy link

@dzmitar dzmitar left a comment

Choose a reason for hiding this comment

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

Also, I think Mike will offer to remove # type: ignores.

lib/sqlalchemy/orm/mapped_collection.py Outdated Show resolved Hide resolved
self,
) -> tuple[
Callable[[_KT, _KT], KeyFuncDict[_KT, _KT]],
tuple[Any, dict[_KT, _KT] | dict[_KT, _KT]],
Copy link

Choose a reason for hiding this comment

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

| dict[_KT, _KT] looks redundant.

Choose a reason for hiding this comment

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

Also | is not supported by Python 3.7 which SQLA must support. So only Union[] can be used.

@@ -223,7 +256,7 @@ def attribute_keyed_dict(


def keyfunc_mapping(
keyfunc: Callable[[Any], _KT],
keyfunc: Callable[[_KT], _KT],
Copy link

Choose a reason for hiding this comment

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

I suggest creating aliases for Callable[[_KT], _KT] and KeyFuncDict[_KT, _KT] and reuse them.

@g-kisenkov
Copy link

g-kisenkov commented Jan 19, 2023

For Untyped decorator makes function * untyped cases try typing the decorators to return a generic function:

Copy link

@g-kisenkov g-kisenkov left a comment

Choose a reason for hiding this comment

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

def _table_key(c: KeyedColumnElement[_KT]) -> Optional[_KT]:
if not isinstance(c.table, expression.TableClause):
return None
else:
return c.table.key # type: ignore

cols = [
coercions.expect(roles.ColumnArgumentRole, q, argname="mapping_spec")
for q in util.to_list(mapping_spec)
]
keyfunc = _PlainColumnGetter(cols) # type: ignore

These 2 places make me really scratch my head. Since in the 2nd snippet we have cols: list[ColumnElement] but in the 1st one we eventually expect KeyedColumnElement.

Maybe there's a way to loosen all of the instances of KeyedColumnElement throughout the module up to plain ColumnElement and then create a Union[ColumnElement, KeyedColumnElement] with an assert narrowing the type down in the final branch of the 1st snippet, since this is the only place that actually expects a KeyedColumnElement.

Are these KeyedColumnElement types just run-time collected or there's a reason to have them that strict in the whole module?

Maybe it's also possible to add another @overload for coercions.expect to narrow cols down to KeyedColumnElement in the 2nd snippet and leave all of the KeyedColumnElement intact.

Not sure if I'm just overthinking it and it's OK to just leave it type: ignore'ed or it's a legitimate way of thinking.

Overall I'm pretty much done with reviewing the module and I think that all of the rest instances of type: ignore can be left in place. Just try to consider this and my previous comment if it doesn't take too much time and ship it off to the upstream repo.

@mlatysh mlatysh force-pushed the issue_6810_type_annotate_sqlalchemy.orm.mapped_collection branch from e0a6cac to fcd123b Compare January 23, 2023 22:22
@mlatysh mlatysh force-pushed the issue_6810_type_annotate_sqlalchemy.orm.mapped_collection branch from fc109bc to a46a5db Compare January 23, 2023 22:25
@mlatysh
Copy link
Author

mlatysh commented Jan 25, 2023

PR was merged to original repo, sqlalchemy#9140, closing this one

@mlatysh mlatysh closed this Jan 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants