Skip to content

[ty] stop special-casing str constructor#24514

Merged
carljm merged 1 commit intomainfrom
cjm/strcon
Apr 9, 2026
Merged

[ty] stop special-casing str constructor#24514
carljm merged 1 commit intomainfrom
cjm/strcon

Conversation

@carljm
Copy link
Copy Markdown
Contributor

@carljm carljm commented Apr 9, 2026

Summary

Fixes astral-sh/ty#3243

Remove our hardcoded handling of the str constructor, in favor of just using the typeshed definition.

A side effect here is that we lose our precise inference of str("foo") as Literal["foo"] instead of str. This is behavior that no other type checker has, and really the right way to provide it would be via an additional overload of str.__new__ in typeshed, rather than via hardcoding. We could preserve this behavior in this PR, but it involves hardcoding KnownClass::Str handling deep inside the call-constructor code, and it seems preferable to avoid that.

Test Plan

Added an mdtest, adjusted mdtest expectations.

@astral-sh-bot astral-sh-bot Bot added the ty Multi-file analysis & type inference label Apr 9, 2026
@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot Bot commented Apr 9, 2026

Typing conformance results

No changes detected ✅

Current numbers
The percentage of diagnostics emitted that were expected errors held steady at 87.72%. The percentage of expected errors that received a diagnostic held steady at 82.85%. The number of fully passing files held steady at 74/132.

@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot Bot commented Apr 9, 2026

Memory usage report

Summary

Project Old New Diff Outcome
prefect 715.72MB 716.87MB +0.16% (1.15MB)
sphinx 263.86MB 264.09MB +0.08% (227.96kB)
trio 117.51MB 117.57MB +0.05% (60.55kB)
flake8 47.93MB 47.96MB +0.07% (33.61kB)

Significant changes

Click to expand detailed breakdown

prefect

Name Old New Diff Outcome
infer_expression_types_impl 61.71MB 62.21MB +0.81% (510.50kB)
infer_definition_types 89.62MB 89.93MB +0.35% (319.65kB)
infer_scope_types_impl 54.10MB 54.23MB +0.24% (131.30kB)
Type<'db>::class_member_with_policy_ 18.01MB 18.06MB +0.27% (49.42kB)
Type<'db>::member_lookup_with_policy_ 16.37MB 16.40MB +0.18% (30.35kB)
Type<'db>::apply_specialization_ 3.66MB 3.69MB +0.75% (28.12kB)
infer_expression_type_impl 13.32MB 13.34MB +0.14% (19.63kB)
Type<'db>::apply_specialization_::interned_arguments 2.93MB 2.95MB +0.58% (17.34kB)
StaticClassLiteral<'db>::implicit_attribute_inner_ 10.00MB 10.01MB +0.14% (14.36kB)
Type<'db>::class_member_with_policy_::interned_arguments 9.74MB 9.75MB +0.13% (12.80kB)
Type<'db>::member_lookup_with_policy_::interned_arguments 5.88MB 5.89MB +0.21% (12.70kB)
StaticClassLiteral<'db>::implicit_attribute_inner_::interned_arguments 5.30MB 5.31MB +0.22% (11.81kB)
all_narrowing_constraints_for_expression 7.17MB 7.18MB +0.10% (7.31kB)
all_negative_narrowing_constraints_for_expression 2.63MB 2.64MB +0.14% (3.70kB)
loop_header_reachability 439.54kB 441.66kB +0.48% (2.12kB)
... 24 more

sphinx

Name Old New Diff Outcome
infer_expression_types_impl 20.94MB 21.03MB +0.43% (91.96kB)
infer_definition_types 23.82MB 23.86MB +0.16% (39.56kB)
Type<'db>::class_member_with_policy_ 7.70MB 7.72MB +0.22% (17.48kB)
infer_scope_types_impl 15.48MB 15.50MB +0.10% (16.38kB)
Type<'db>::apply_specialization_ 1.65MB 1.66MB +0.74% (12.55kB)
Type<'db>::member_lookup_with_policy_ 6.54MB 6.55MB +0.15% (9.80kB)
Type<'db>::apply_specialization_::interned_arguments 1.46MB 1.46MB +0.54% (8.05kB)
StaticClassLiteral<'db>::implicit_attribute_inner_ 2.40MB 2.40MB +0.24% (5.91kB)
StaticClassLiteral<'db>::implicit_attribute_inner_::interned_arguments 1.93MB 1.93MB +0.26% (5.06kB)
Type<'db>::class_member_with_policy_::interned_arguments 4.05MB 4.05MB +0.12% (4.88kB)
Type<'db>::member_lookup_with_policy_::interned_arguments 2.68MB 2.69MB +0.18% (4.88kB)
infer_expression_type_impl 2.93MB 2.94MB +0.13% (3.98kB)
all_narrowing_constraints_for_expression 2.34MB 2.34MB +0.07% (1.59kB)
loop_header_reachability 379.96kB 381.55kB +0.42% (1.59kB)
enum_metadata 738.52kB 739.52kB +0.13% (1016.00B)
... 14 more

trio

Name Old New Diff Outcome
infer_expression_types_impl 7.03MB 7.05MB +0.27% (19.71kB)
Type<'db>::class_member_with_policy_ 2.04MB 2.05MB +0.41% (8.45kB)
Type<'db>::apply_specialization_ 729.46kB 733.61kB +0.57% (4.14kB)
Type<'db>::member_lookup_with_policy_ 1.83MB 1.84MB +0.22% (4.08kB)
StaticClassLiteral<'db>::implicit_attribute_inner_ 750.50kB 754.00kB +0.47% (3.50kB)
StaticClassLiteral<'db>::implicit_attribute_inner_::interned_arguments 599.25kB 602.25kB +0.50% (3.00kB)
Type<'db>::apply_specialization_::interned_arguments 641.56kB 644.30kB +0.43% (2.73kB)
infer_definition_types 7.63MB 7.63MB +0.03% (2.51kB)
Type<'db>::class_member_with_policy_::interned_arguments 1.12MB 1.13MB +0.19% (2.23kB)
infer_scope_types_impl 4.77MB 4.78MB +0.04% (2.19kB)
Type<'db>::member_lookup_with_policy_::interned_arguments 929.60kB 931.53kB +0.21% (1.93kB)
infer_deferred_types 2.35MB 2.35MB +0.06% (1.45kB)
FunctionType<'db>::signature_ 1.06MB 1.06MB +0.07% (836.00B)
function_known_decorators 922.11kB 922.69kB +0.06% (600.00B)
Specialization 464.83kB 465.38kB +0.12% (560.00B)
... 22 more

flake8

Name Old New Diff Outcome
infer_expression_types_impl 1.05MB 1.06MB +1.09% (11.67kB)
infer_definition_types 1.87MB 1.87MB +0.30% (5.73kB)
infer_scope_types_impl 992.99kB 995.41kB +0.24% (2.41kB)
Type<'db>::class_member_with_policy_ 580.04kB 582.07kB +0.35% (2.04kB)
infer_deferred_types 693.52kB 694.97kB +0.21% (1.45kB)
Type<'db>::apply_specialization_::interned_arguments 204.61kB 205.86kB +0.61% (1.25kB)
Type<'db>::member_lookup_with_policy_ 493.21kB 494.26kB +0.21% (1.04kB)
Type<'db>::apply_specialization_ 218.44kB 219.45kB +0.46% (1.02kB)
Type<'db>::class_member_with_policy_::interned_arguments 311.80kB 312.71kB +0.29% (936.00B)
FunctionType<'db>::signature_ 360.50kB 361.32kB +0.23% (836.00B)
Type<'db>::member_lookup_with_policy_::interned_arguments 233.59kB 234.20kB +0.26% (624.00B)
function_known_decorators 318.36kB 318.95kB +0.18% (600.00B)
StaticClassLiteral<'db>::implicit_attribute_inner_ 313.45kB 313.99kB +0.17% (560.00B)
StaticClassLiteral<'db>::implicit_attribute_inner_::interned_arguments 255.38kB 255.84kB +0.18% (480.00B)
Specialization 163.03kB 163.47kB +0.27% (448.00B)
... 20 more

@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot Bot commented Apr 9, 2026

ecosystem-analyzer results

Lint rule Added Removed Changed
invalid-argument-type 0 1 2
invalid-assignment 0 0 1
Total 0 1 3

Raw diff:

dd-trace-py (https://github.com/DataDog/dd-trace-py)
- ddtrace/propagation/_database_monitoring.py:136:13 error[invalid-assignment] Invalid subscript assignment with key of type `Literal["ddsh"]` and value of type `LiteralString` on object of type `dict[Literal["ddps", "dde", "ddpv", "dddbs"], Unknown | str]`
+ ddtrace/propagation/_database_monitoring.py:136:13 error[invalid-assignment] Invalid subscript assignment with key of type `Literal["ddsh"]` and value of type `str` on object of type `dict[Literal["ddps", "dde", "ddpv", "dddbs"], Unknown | str]`

mitmproxy (https://github.com/mitmproxy/mitmproxy)
- mitmproxy/io/tnetstring.py:191:20 error[invalid-argument-type] Argument to class `str` is incorrect: Expected `bytes | bytearray`, found `memoryview[int]`

pip (https://github.com/pypa/pip)
- src/pip/_vendor/requests/models.py:937:41 error[invalid-argument-type] Argument to class `str` is incorrect: Expected `str`, found `Unknown | None`
+ src/pip/_vendor/requests/models.py:937:41 error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `str`, found `Unknown | None`

scikit-learn (https://github.com/scikit-learn/scikit-learn)
- sklearn/datasets/_lfw.py:469:60 error[invalid-argument-type] Argument to class `str` is incorrect: Expected `bytes | bytearray`, found `str`
+ sklearn/datasets/_lfw.py:469:60 error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Buffer`, found `str`

Full report with detailed diff (timing results)

@carljm carljm marked this pull request as ready for review April 9, 2026 07:33
Copy link
Copy Markdown
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

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

Yeah, agreed, this special-casing just isn't worth it

@carljm carljm merged commit a45f96d into main Apr 9, 2026
53 checks passed
@carljm carljm deleted the cjm/strcon branch April 9, 2026 07:40
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we could have also fixed it by implementing this TODO? (which I couldn't implement when I added this code here because we didn't have support for protocols back then, I believe). I'm not opposed to removing this special handling, but it does lead to some minor regressions (e.g. being able to infer str(<literal>) as Literal[<literal>]). On the other hand, having less code is always good. I'm fine either way.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, that's right -- fixing that TODO and matching our special-cased constructor signature to the typeshed one would have been the other way to fix this. I felt that if we think inferring str("foo") as Literal["foo"] is important, it would be better to implement this via an additional overload in typeshed, rather than by maintaining our own hardcoded copy of the str constructor overloads from typeshed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Now I'm curious: how would you model this by adding an additional overload?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I admit I didn't try this out (or even think through it in depth), since I suspect that this particular precision is not important, but it seemed to me that an overload like this would do it?

@overload
def __new__[T: LiteralString](cls, object: T) -> T: ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

memoryview not accepted in str constructor

4 participants