Problem
async def is not represented anywhere in the emitted schema. git grep -i "is_async"
on main returns nothing under codeanalyzer/schema/ or codeanalyzer/syntactic_analysis/.
The builder does match ast.AsyncFunctionDef — but only to find callables, never to
record what it found; PyCallable.kind is set to the literal "function" either way.
Verified on main (6f02581), fixture method async def fetch(self):
method 'fetch' kind=function decorators=["trace('method')"]
Nothing distinguishes it from a sync method. The only way to recover async-ness is to
slice module.source[span.bytes] and re-parse the text the analyzer already parsed.
This also hides await sites, async generators, and async with / async for from
anyone reading the tree rather than the source.
Scope boundary
Adds an async marker to callables. Does not model await as a distinct CFG or DDG
node kind, does not add async-aware dataflow, and does not touch the decorator issues
(#127, #128, #129).
Goals
Caveats and known risks
- Schema v2 change — enters at
designing-cldk-changes. Additive and defaulted, so
monotonicity and existing consumers are unaffected. kind vs a boolean is the decision to settle.kind is already a discriminant
("function", "class", "module", "external"); adding "async_function" to it
would break every consumer switching on kind, whereas a separate boolean leaves
kind alone. Pick one deliberately — do not do both.- Sibling analyzers. TypeScript has
async too. The field name should be the
canonical cross-language one, decided once here rather than renamed later. @staticmethod / @classmethod / @property are in the same situation — recoverable
only by string-matching decorators. Deliberately out of scope, but the same decision
shape; worth noting so it is not re-derived later.
Definition of done
- The fixture emits the async marker set on
Account.fetch and unset on Account.helper - A module-level
async def and a nested async def closure both carry it - An async generator carries it and is not confused with a plain generator
analysis.json(-a 1) ⊆ ... ⊆ (-a 4) still holds- Neo4j exposes the property and a query can select async callables without touching source
Problem
async defis not represented anywhere in the emitted schema.git grep -i "is_async"on
mainreturns nothing undercodeanalyzer/schema/orcodeanalyzer/syntactic_analysis/.The builder does match
ast.AsyncFunctionDef— but only to find callables, never torecord what it found;
PyCallable.kindis set to the literal"function"either way.Verified on
main(6f02581), fixture methodasync def fetch(self):Nothing distinguishes it from a sync method. The only way to recover async-ness is to
slice
module.source[span.bytes]and re-parse the text the analyzer already parsed.This also hides
awaitsites, async generators, andasync with/async forfromanyone reading the tree rather than the source.
Scope boundary
Adds an async marker to callables. Does not model
awaitas a distinct CFG or DDGnode kind, does not add async-aware dataflow, and does not touch the decorator issues
(#127, #128, #129).
Goals
PyCallablecarries an async marker, available from L1async defat every depth: module-level, method, nested closureasync defcontainingyield) are not misreported:PyCallableSCHEMA_VERSION(additive)Caveats and known risks
designing-cldk-changes. Additive and defaulted, somonotonicity and existing consumers are unaffected.
kindvs a boolean is the decision to settle.kindis already a discriminant(
"function","class","module","external"); adding"async_function"to itwould break every consumer switching on
kind, whereas a separate boolean leaveskindalone. Pick one deliberately — do not do both.asynctoo. The field name should be thecanonical cross-language one, decided once here rather than renamed later.
@staticmethod/@classmethod/@propertyare in the same situation — recoverableonly by string-matching
decorators. Deliberately out of scope, but the same decisionshape; worth noting so it is not re-derived later.
Definition of done
Account.fetchand unset onAccount.helperasync defand a nestedasync defclosure both carry itanalysis.json(-a 1) ⊆ ... ⊆ (-a 4)still holds