Visitor used to print existing annotations in a file. The main difference from TypeStrVisitor is a better treatment of unbound types. Notes: * This visitor doesn't add imports necessary for annotations, this is done separately by ImportTracker. * It can print all kinds of
| 225 | |
| 226 | |
| 227 | class AnnotationPrinter(TypeStrVisitor): |
| 228 | """Visitor used to print existing annotations in a file. |
| 229 | |
| 230 | The main difference from TypeStrVisitor is a better treatment of |
| 231 | unbound types. |
| 232 | |
| 233 | Notes: |
| 234 | * This visitor doesn't add imports necessary for annotations, this is done separately |
| 235 | by ImportTracker. |
| 236 | * It can print all kinds of types, but the generated strings may not be valid (notably |
| 237 | callable types) since it prints the same string that reveal_type() does. |
| 238 | * For Instance types it prints the fully qualified names. |
| 239 | """ |
| 240 | |
| 241 | # TODO: Generate valid string representation for callable types. |
| 242 | # TODO: Use short names for Instances. |
| 243 | def __init__( |
| 244 | self, |
| 245 | stubgen: BaseStubGenerator, |
| 246 | known_modules: list[str] | None = None, |
| 247 | local_modules: list[str] | None = None, |
| 248 | ) -> None: |
| 249 | super().__init__(options=mypy.options.Options()) |
| 250 | self.stubgen = stubgen |
| 251 | self.known_modules = known_modules |
| 252 | self.local_modules = local_modules or ["builtins"] |
| 253 | |
| 254 | def visit_any(self, t: AnyType) -> str: |
| 255 | s = super().visit_any(t) |
| 256 | self.stubgen.import_tracker.require_name(s) |
| 257 | return s |
| 258 | |
| 259 | def visit_unbound_type(self, t: UnboundType) -> str: |
| 260 | s = t.name |
| 261 | fullname = self.stubgen.resolve_name(s) |
| 262 | if fullname == "typing.Union": |
| 263 | return " | ".join([item.accept(self) for item in t.args]) |
| 264 | if fullname == "typing.Optional": |
| 265 | if len(t.args) == 1: |
| 266 | return f"{t.args[0].accept(self)} | None" |
| 267 | return self.stubgen.add_name("_typeshed.Incomplete") |
| 268 | if fullname in TYPING_BUILTIN_REPLACEMENTS: |
| 269 | s = self.stubgen.add_name(TYPING_BUILTIN_REPLACEMENTS[fullname], require=True) |
| 270 | if self.known_modules is not None and "." in s: |
| 271 | # see if this object is from any of the modules that we're currently processing. |
| 272 | # reverse sort so that subpackages come before parents: e.g. "foo.bar" before "foo". |
| 273 | for module_name in self.local_modules + sorted(self.known_modules, reverse=True): |
| 274 | if s.startswith(module_name + "."): |
| 275 | if module_name in self.local_modules: |
| 276 | s = s[len(module_name) + 1 :] |
| 277 | arg_module = module_name |
| 278 | break |
| 279 | else: |
| 280 | arg_module = s[: s.rindex(".")] |
| 281 | if arg_module not in self.local_modules: |
| 282 | self.stubgen.import_tracker.add_import(arg_module, require=True) |
| 283 | elif s == "NoneType": |
| 284 | # when called without analysis all types are unbound, so this won't hit |
no outgoing calls
no test coverage detected
searching dependent graphs…