| 489 | |
| 490 | |
| 491 | class AttributeStubsGenerator(StubsGenerator): |
| 492 | def __init__(self, name, attribute): # type: (str, Any)-> None |
| 493 | self.name = name |
| 494 | self.attr = attribute |
| 495 | |
| 496 | def parse(self): |
| 497 | if self in _visited_objects: |
| 498 | return |
| 499 | _visited_objects.append(self) |
| 500 | |
| 501 | def is_safe_to_use_repr(self, value): |
| 502 | if value is None or isinstance(value, (int, str)): |
| 503 | return True |
| 504 | if isinstance(value, (float, complex)): |
| 505 | try: |
| 506 | eval(repr(value)) |
| 507 | return True |
| 508 | except (SyntaxError, NameError): |
| 509 | return False |
| 510 | if isinstance(value, (list, tuple, set)): |
| 511 | for x in value: |
| 512 | if not self.is_safe_to_use_repr(x): |
| 513 | return False |
| 514 | return True |
| 515 | if isinstance(value, dict): |
| 516 | for k, v in value.items(): |
| 517 | if not self.is_safe_to_use_repr(k) or not self.is_safe_to_use_repr(v): |
| 518 | return False |
| 519 | return True |
| 520 | return False |
| 521 | |
| 522 | def to_lines(self): # type: () -> List[str] |
| 523 | if self.is_safe_to_use_repr(self.attr): |
| 524 | return ["{name} = {repr}".format(name=self.name, repr=repr(self.attr))] |
| 525 | |
| 526 | # special case for modules |
| 527 | # https://github.com/sizmailov/pybind11-stubgen/issues/43 |
| 528 | if type(self.attr) is type(os) and hasattr(self.attr, "__name__"): |
| 529 | return ["{name} = {repr}".format(name=self.name, repr=self.attr.__name__)] |
| 530 | |
| 531 | # special case for PyCapsule |
| 532 | # https://github.com/sizmailov/pybind11-stubgen/issues/86 |
| 533 | attr_type = type(self.attr) |
| 534 | if attr_type.__name__ == "PyCapsule" and attr_type.__module__ == "builtins": |
| 535 | return ["{name}: typing.Any # PyCapsule()".format(name=self.name)] |
| 536 | |
| 537 | value_lines = repr(self.attr).split("\n") |
| 538 | typename = self.fully_qualified_name(type(self.attr)) |
| 539 | |
| 540 | if len(value_lines) == 1: |
| 541 | value = value_lines[0] |
| 542 | # remove random address from <foo.Foo object at 0x1234> |
| 543 | value = re.sub(r" at 0x[0-9a-fA-F]+>", ">", value) |
| 544 | if value == "<{typename} object>".format(typename=typename): |
| 545 | value_comment = "" |
| 546 | else: |
| 547 | value_comment = " # value = {value}".format(value=value) |
| 548 | return [ |