An immutable object holding a source code fragment. When using Source(...), the source lines are deindented.
| 14 | |
| 15 | |
| 16 | class Source: |
| 17 | class="st">"""An immutable object holding a source code fragment. |
| 18 | |
| 19 | When using Source(...), the source lines are deindented. |
| 20 | class="st">""" |
| 21 | |
| 22 | def __init__(self, obj: object = None) -> None: |
| 23 | if not obj: |
| 24 | self.lines: list[str] = [] |
| 25 | self.raw_lines: list[str] = [] |
| 26 | elif isinstance(obj, Source): |
| 27 | self.lines = obj.lines |
| 28 | self.raw_lines = obj.raw_lines |
| 29 | elif isinstance(obj, tuple | list): |
| 30 | self.lines = deindent(x.rstrip(class="st">"\n") for x in obj) |
| 31 | self.raw_lines = list(x.rstrip(class="st">"\n") for x in obj) |
| 32 | elif isinstance(obj, str): |
| 33 | self.lines = deindent(obj.split(class="st">"\n")) |
| 34 | self.raw_lines = obj.split(class="st">"\n") |
| 35 | else: |
| 36 | try: |
| 37 | rawcode = getrawcode(obj) |
| 38 | src = inspect.getsource(rawcode) |
| 39 | except TypeError: |
| 40 | src = inspect.getsource(obj) class="cm"># type: ignore[arg-type] |
| 41 | self.lines = deindent(src.split(class="st">"\n")) |
| 42 | self.raw_lines = src.split(class="st">"\n") |
| 43 | |
| 44 | def __eq__(self, other: object) -> bool: |
| 45 | if not isinstance(other, Source): |
| 46 | return NotImplemented |
| 47 | return self.lines == other.lines |
| 48 | |
| 49 | class="cm"># Ignore type because of https://github.com/python/mypy/issues/4266. |
| 50 | __hash__ = None class="cm"># type: ignore |
| 51 | |
| 52 | @overload |
| 53 | def __getitem__(self, key: int) -> str: ... |
| 54 | |
| 55 | @overload |
| 56 | def __getitem__(self, key: slice) -> Source: ... |
| 57 | |
| 58 | def __getitem__(self, key: int | slice) -> str | Source: |
| 59 | if isinstance(key, int): |
| 60 | return self.lines[key] |
| 61 | else: |
| 62 | if key.step not in (None, 1): |
| 63 | raise IndexError(class="st">"cannot slice a Source with a step") |
| 64 | newsource = Source() |
| 65 | newsource.lines = self.lines[key.start : key.stop] |
| 66 | newsource.raw_lines = self.raw_lines[key.start : key.stop] |
| 67 | return newsource |
| 68 | |
| 69 | def __iter__(self) -> Iterator[str]: |
| 70 | return iter(self.lines) |
| 71 | |
| 72 | def __len__(self) -> int: |
| 73 | return len(self.lines) |
no outgoing calls