Danny Yang
90d · built 2026-08-09
90-day totals
- Commits
- 113
- Grow
- 4.2
- Maintenance
- 2.9
- Fixes
- 6.6
- Total ETV
- 13.6
Where this dev ranks
Percentile against the global top-100 leaderboard (all-time totals).
- By commits
- Top 21 %
- By Growth share
- Top 65 %
30-day trajectory
Last 30 days vs. the 30 days before. Up arrows on Growth and ETV mean improvement; up arrow on Fixes share means more time on fixes (worse).
↑+53.1 %
vs 32 prior
↑+10.7 pp
recent vs prior
↑+10.5 pp
recent vs prior
Daily performance
Daily ETV, stacked by Growth, Maintenance and Fixes.
Work-mix over time
Share of Growth / Maintenance / Fixes over a rolling 7-day window. Reads as 'where is effort flowing right now'.
Repository spread
Where this developer's commits land. Concentrated work (top1 > 80%) vs polymath spread (top1 < 30%).
Most impactful commits
Top 20 by ETV in the 90-day window.
- 1.2ETVfix Pydantic alias_generator (#2946) Summary: Fixes #2942 teaching Pydantic config parsing to recognize built-in alias generators from pydantic.alias_generators, carry that through model metadata, and synthesize generated __init__ keyword names when a field has no explicit alias. closes https://github.com/facebook/pyrefly/pull/2946 Reviewed By: rchen152, connernilsen Differential Revision: D113289645 fbshipit-source-id: f4b9ca768768a5f4b79e0d46cd9aac982f85472cgithub.com-facebook-pyrefly · 18a7a3b6 · 2026-07-24
- 0.7ETVOnly treat written `*args: Any, **kwargs: Any` as a gradual signature Summary: Per the typing spec, a signature whose `*args` and `**kwargs` are both typed `Any` is equivalent to `...`. Pyrefly detected this by inspecting the (already-substituted) parameter types, so `Proto[Any]` over `*args: T, **kwargs: T` was wrongly treated as gradual and accepted incompatible callables. Record the property at definition time in a `FuncMetadata` flag instead, so an `Any` introduced by type-parameter substitution no longer counts. Fixes the `callables_annotation` conformance mismatch. Reviewed By: rchen152 Differential Revision: D114691415 fbshipit-source-id: bf27b1a34d4426cffee214d77418fe248ed0b5bcgithub.com-facebook-pyrefly · 40beb729 · 2026-08-04
- 0.6ETVHandle error swallowing context manager in reachability/termination calculation Summary: We can't determine whether a context manager swallows errors at the binding step, so whether or not a raise inside a context manager terminates control flow needs to be deferred to the solving step. This is similar to our mechanisms for handling calls to never-returning functions, and various exhaustiveness checks that depend on the narrowed types. Reviewed By: grievejia Differential Revision: D114761866 fbshipit-source-id: 1dd4f2d06eae2778c59a8b3ff391f474391a1859github.com-facebook-pyrefly · 33b28795 · 2026-08-05
- 0.5ETVfix markdown diagnostic emission/parsing Summary: Now that lsp-types is updated for 3.18, we can fix this bug fixes https://github.com/facebook/pyrefly/issues/3823 Reviewed By: stroxler Differential Revision: D109722234 fbshipit-source-id: 7be2e9d3ecf03e66c0cf8d6c78d496f17d951b3agithub.com-facebook-pyrefly · 81db4cab · 2026-06-26
- 0.5ETVstubgen: emit synthesized `__init__` for dataclasses (#3586) Summary: Pull Request resolved: https://github.com/facebook/pyrefly/pull/3586 closes https://github.com/facebook/pyrefly/issues/3221 Dataclasses (and similar patterns like NamedTuples) generate their `__init__` at type-check time rather than declaring it in source. Previously, stubgen would omit the `__init__` entirely for these classes, producing stubs that lost the constructor signature. Look up `KeyClassSynthesizedFields` in the answers to find the synthesized `__init__` type (a `Type::Function` with the full `Callable` signature), then convert its `Param` list into stub parameters. Only emitted when no explicit `__init__` exists in the source. Reviewed By: rchen152 Differential Revision: D106327984 fbshipit-source-id: f7476513b3234393945e6737dfca32cea56f8297github.com-facebook-pyrefly · fc794752 · 2026-05-26
- 0.4ETVfilter overloads by self-type during protocol conformance Summary: Checking a value against a protocol's overloaded method ignored the overloads' explicit `self:` annotations. A `timedelta` receiver matching a protocol like pandas-stubs `Series.__truediv__` wrongly selected the first (`int`) overload, producing a spurious unsupported-operation error. The unbound class-access path (`as_class_attribute`) already filtered overloads by `self:`, but the protocol-conformance lookup did not. When resolving a candidate's member during a protocol structural-subtyping check, look the instance attribute up via `Instance::of_protocol` so overloads whose `self:` type is incompatible with the concrete receiver are dropped before binding. The existing class-access filter is extracted into a shared `filter_overloads_by_self_type` helper used by both paths. fixes https://github.com/facebook/pyrefly/issues/3819 Reviewed By: rchen152 Differential Revision: D108626551 fbshipit-source-id: 447050b074a6e7b073e761143f8873af0ad60274github.com-facebook-pyrefly · 1a171757 · 2026-06-15
- 0.4ETVimprove typed dict error messages Summary: fixes https://github.com/facebook/pyrefly/issues/3210 1. make invalid assignments report bad-assignment rather than bad-typed-dict-key, the key exists but the value is wrong 2. print out anonymous typed dict errors differently 3. for anonymous typed dict index errors, emit bad-index rather than bad-typed-dict-key, since anonymous typed dict is an implementation detail Reviewed By: grievejia Differential Revision: D105733104 fbshipit-source-id: 796a15ea7c98133c2ddf54d96bdba03bbbdab589github.com-facebook-pyrefly · 7c7916b1 · 2026-05-19
- 0.4ETVRead sequence element captures relationally from the narrowed subject Summary: After the facet `isinstance` parent-filter, matching a union of tuples narrows the subject to the matching member, but sibling element captures still read the widened join: `case (str() as x, y)` on `tuple[str, int] | tuple[int, str]` narrows the match subject to `tuple[str, int]`, but `y` still reads from `tuple[str, int] | tuple[int, str]` and has type `int | str` instead of `int` The reason is that a sequence sub-pattern name binds to `UnpackedValue(subject_idx, Index(i))`, and `subject_idx` was narrowed only by `IsSequence + LenEq` -- not by the sibling elements' constraints. The proposed solution in this diff is to fold each leaf sibling element constraint into the subject narrow. A new helper maps a sub-pattern to the atomic narrow op it imposes on its element; these become facet narrows added to the subject's `Narrow` binding. Constraints are derived from the pattern AST, so there is no binding cycle. For https://github.com/facebook/pyrefly/issues/3805 Reviewed By: stroxler Differential Revision: D111908477 fbshipit-source-id: a639d50aecd8e70a8a5a0c4bbe595bcefb0b79b5github.com-facebook-pyrefly · 7a48e983 · 2026-07-23
- 0.4ETVstubgen: render callable-typed values as typing.Callable[...] annotations Summary: resolves https://github.com/facebook/pyrefly/pull/3877 An overload set whose signatures have differing return types has no single faithful return type, but it is still a callable. Emitting bare `Incomplete` discarded that information; render `Callable[..., Incomplete]` instead so the stub conveys callability while leaving the return type unspecified. Reviewed By: stroxler Differential Revision: D109264857 fbshipit-source-id: d4b1868929564f4bf2615b8b5ed17d6f32b794afgithub.com-facebook-pyrefly · 6f34bb9c · 2026-06-22
- 0.4ETVuse --typeshed-path when deriving module names for checked files Summary: if you point pyrefly at a typeshed checkout with `--typeshed-path` and ask it to check that typeshed's own stubs, every special form breaks: `_T = TypeVar("_T")` in `typing.pyi` reports: > Expected a type form, got instance of TypeVar`, `Protocol` becomes an `Invalid base class `SpecialExport::defined_in` only treats `TypeVar` as special when the enclosing module is literally `typing`, but `handle_from_module_path` derived the module name from `explicit_search_path + site_package_path + import_root` only. `typeshed_path` was known to `find_module` for import resolution but not to module naming, so `<typeshed>/stdlib/typing.pyi` fell through to the import_root heuristic and got named `stdlib.typing`. the fix has 2 parts - `handle_from_module_path` now considers `<typeshed_path>/stdlib`, ranked below explicit search paths (user intent still wins) but above the import_root heuristic - `--typeshed-path` now goes through `absolute_path_parser`, like `--search-path` already does. CLI file paths get absolutized in `files.rs`, so a relative `--typeshed-path .` produced `./stdlib`, which never `strip_prefix`-matches an absolute path. without this half the first half does nothing for the common invocation. **this diff unblocks running pyrefly in typeshed CI** Reviewed By: rchen152 Differential Revision: D114553005 fbshipit-source-id: 4e8be6aa258ebdffcdcfb62e4abaa7aa5f6061afgithub.com-facebook-pyrefly · 39c36d78 · 2026-08-03
- 0.3ETVResolve annotation-only class attributes in stub files Summary: In stubs, an annotation-only class attribute like `x: int` should be treated like a declaration that is in scope for the rest of the class body. For source files this may not be safe to do since the attribute may not be initialized, but for stubs it's OK since it doesn't actually run. fixes https://github.com/facebook/pyrefly/issues/4411 Reviewed By: rchen152 Differential Revision: D115147935 fbshipit-source-id: 2e7a6da66fd660cfd44f9caf4b08606b470543d7github.com-facebook-pyrefly · b5bc9e85 · 2026-08-07
- 0.3ETVFlag enclosing-class legacy TypeVars used in nested classes Summary: A legacy (pre-PEP-695) TypeVar declared as a type parameter of an enclosing class is out of scope inside a nested class; the nested class does not inherit the outer class's type parameters. Previously pyrefly either silently resolved such a reference to the outer class's parameter or let the nested class re-adopt the TypeVar as its own, so no error was reported. The fix is to track whether a name lookup crosses a class-annotation scope: a class's legacy type parameters live in its class-annotation scope and are only visible from the innermost enclosing class (its body and methods). Once the walk crosses one class-annotation scope, an outer class's type parameters are out of scope and fall through to the module-level `TypeVar` (leaving a raw, out-of-scope type variable), which we flag & degrade to Any (error) to avoid cascading errors. for https://github.com/facebook/pyrefly/issues/2454 Reviewed By: rchen152 Differential Revision: D114766377 fbshipit-source-id: a8672189e07333b267d8a9e4b9dce60fb2e98c30github.com-facebook-pyrefly · b88bdf2e · 2026-08-06
- 0.3ETVTreat a same-arity wildcard sequence pattern over a tuple subject as a catch-all Summary: fixes https://github.com/facebook/pyrefly/issues/2932 If we are matching on a tuple of known length, when we have a wildcard sequence pattern of the same length we should detect that it's exhaustive. resolves https://github.com/facebook/pyrefly/pull/2963 Reviewed By: kinto0 Differential Revision: D111925917 fbshipit-source-id: e1cf7a838c846ed13fa21f5a3573daefa401f490github.com-facebook-pyrefly · f960ee7f · 2026-07-27
- 0.3ETVadd implicit-reexport error kind Summary: Implements the typing-spec rule (pyright's reportPrivateImportUsage): a name a module only makes available through a plain `import`/`from ... import ...` is not part of that module's public interface, so importing it from there is fragile and should be flagged. Detection reuses the export metadata we already track (DefinitionStyle): a name is an implicit re-export unless it is defined locally, redundantly aliased (`from x import y as y`), listed in `__all__`, or brought in via a wildcard. The check runs during import resolution in `solve_import` and defaults to `ignore` (opt-in). fixes https://github.com/facebook/pyrefly/issues/3724 Reviewed By: stroxler Differential Revision: D113313927 fbshipit-source-id: 4ec80ba1f14724507aa22248501897fd420d8c2dgithub.com-facebook-pyrefly · 8d44ef99 · 2026-07-23
- 0.3ETVhandle __getattr__ in structural subtyping Summary: In protocol subtyping, allow `__getattr__` and `__getattribute__` to satisfy protocol members. Some special cases considered: - `__getattribute__` takes precedence over `__getattr__` (unless the former is inherited from object) - the fallback does not apply when looking up something from a class object - some dunders cannot be satisfied by the fallback (including the fallbacks themselves, and some operators). this matches mypy's implementation of these semantics. - derived members are treated as read-only unless a custom `__setattr__` is present Fixes https://github.com/facebook/pyrefly/issues/4077 Reviewed By: grievejia Differential Revision: D111042210 fbshipit-source-id: 0d7d05eb5e884d56f81342c4c85d20361c03ccccgithub.com-facebook-pyrefly · 46774e3b · 2026-08-03
- 0.3ETVdon't offer statement keywords in expression context Summary: if we're in an expression, we don't need to offer keyword completions like try, while, etc. fixes https://github.com/facebook/pyrefly/issues/4067 Reviewed By: ndmitchell Differential Revision: D111056254 fbshipit-source-id: 72ac5f9bd66f088f276e0914e0f5d1342ef644a0github.com-facebook-pyrefly · 9daf80f6 · 2026-07-08
- 0.2ETVimplement reportUnknownArgumentType rule Summary: Add the `unknown-argument-type` error kind (a sub-kind of `implicit-any`), which flags call arguments whose type is an implicit `Any`. fixes https://github.com/facebook/pyrefly/issues/4036 Reviewed By: stroxler Differential Revision: D111274171 fbshipit-source-id: e8a3caa8f9fcf8da4c67d8f349eff28b0f49315fgithub.com-facebook-pyrefly · b4d2622b · 2026-07-25
- 0.2ETVstubgen: annotate implicit class variables as ClassVar Summary: Bare assignments in a class body (e.g. `FILEMAP = {...}`, a method rebinding) are class variables, but stubgen emitted them with a plain type annotation, which denotes an instance attribute rather than a class variable. Wrap the inferred annotation for such class-body assignments in `ClassVar[...]` (emitting the matching `from typing import ClassVar`) fixes https://github.com/facebook/pyrefly/issues/3890 Reviewed By: stroxler Differential Revision: D109306360 fbshipit-source-id: 9532024dbc0607889226fe10b314025e54b15b06github.com-facebook-pyrefly · a8c7a3fc · 2026-06-25
- 0.2ETVReport invalid StrEnum TypedDict assignment keys Summary: TypedDict item assignment already has special handling so valid literal keys and invalid literal keys report TypedDict-specific diagnostics instead of going through `__setitem__`. StrEnum members are string-like but not string literals, so assignments like `td[MyEnum.i] = value` fell through to the generic magic-method path and incorrectly reported that the TypedDict has no `__setitem__`. Keep string-like non-literal keys on the TypedDict assignment path. Uniform extra-item TypedDicts still accept dynamic string keys as before; non-uniform TypedDicts now report that a string literal key is required, which points at the actual key issue instead of suggesting item assignment is unsupported. fixes https://github.com/facebook/pyrefly/issues/4255 Reviewed By: stroxler Differential Revision: D113403263 fbshipit-source-id: 5608c01d3dd3a2c428679568da546c9bcfa0f92cgithub.com-facebook-pyrefly · 9a8fa00f · 2026-07-23
- 0.2ETVstubgen: preserve `__all__` so re-exports survive Summary: Stubgen read `__all__` to decide which module-level names to keep, but then dropped the `__all__` assignment itself. Per PEP 484 a name imported without a redundant `as` alias is re-exported only if it appears in `__all__`, so dropping `__all__` silently un-exported every plainly-imported name (e.g. `from pkg._impl import op; __all__ = ["op"]`). A downstream `from pkg import *` against the stub then fails with `unknown-name`, even though it's clean against the source (real-world: weave, sentry_sdk). Emit `__all__` verbatim when it's a static list/tuple literal, in its original source position. Computed/dynamic `__all__` forms are left as-is (unchanged behavior). Fixes https://github.com/facebook/pyrefly/issues/3924 Reviewed By: stroxler Differential Revision: D109852392 fbshipit-source-id: 49359c49731794605004d69d154596e3cc326dcegithub.com-facebook-pyrefly · 9752acc5 · 2026-06-26