(self, node: Node)
| 164 | ) |
| 165 | |
| 166 | def extract_from_code(self, node: Node) -> ParseResult[str]: |
| 167 | # NB. Ast line reference and col index is on a 1-indexed basis. |
| 168 | lineno = node.lineno |
| 169 | col_offset = node.col_offset |
| 170 | violations: list[Violation] = [] |
| 171 | |
| 172 | if hasattr(node, "decorator_list"): |
| 173 | # From the ast, having a decorator list means we are either a |
| 174 | # function or a class. |
| 175 | assert isinstance( |
| 176 | node, (ast.AsyncFunctionDef, ast.FunctionDef, ast.ClassDef) |
| 177 | ) |
| 178 | |
| 179 | # Scrub past the decorator + 1, lineno 1 index -1 |
| 180 | decorator: ast.expr | None |
| 181 | if len(node.decorator_list) and ( |
| 182 | decorator := get_valid_decorator(node) |
| 183 | ): |
| 184 | # We may have a decorator between cell decorator and function. |
| 185 | # This is invalid serialization, but still possible. |
| 186 | if len(node.decorator_list) > 1 and is_cell_decorator( |
| 187 | decorator, allowed=("cell",) |
| 188 | ): |
| 189 | # We just take the last decorator in this case, which will |
| 190 | # be removed on serialization. |
| 191 | violations.append( |
| 192 | Violation( |
| 193 | "Multiple decorators found, only @app.cell is valid.", |
| 194 | lineno=decorator.lineno, |
| 195 | col_offset=decorator.col_offset, |
| 196 | ) |
| 197 | ) |
| 198 | |
| 199 | decorator = node.decorator_list[-1] |
| 200 | lineno = _none_to_0(decorator.end_lineno) |
| 201 | col_offset = decorator.col_offset - 1 |
| 202 | else: |
| 203 | lineno -= 1 |
| 204 | |
| 205 | code = self.extract_from_offsets( |
| 206 | lineno, |
| 207 | col_offset, |
| 208 | _none_to_0(node.end_lineno) - 1, |
| 209 | _none_to_0(node.end_col_offset), |
| 210 | ) |
| 211 | |
| 212 | # Capture trailing comments after the AST's end position for app.function |
| 213 | # and the setup cell (which is in a with block). |
| 214 | # |
| 215 | # The AST doesn't include comments, so we look for lines after |
| 216 | # node.end_lineno that are at the body indentation level. |
| 217 | # We append trailing code BEFORE dedenting so both get dedented |
| 218 | # by the same amount, preserving relative indentation. |
| 219 | if ( |
| 220 | isinstance( |
| 221 | node, |
| 222 | ( |
| 223 | ast.AsyncFunctionDef, |
no test coverage detected