| 1788 | return Label(name, self, self.type) |
| 1789 | |
| 1790 | def _anon_label( |
| 1791 | self, seed: Optional[str], add_hash: Optional[int] = None |
| 1792 | ) -> _anonymous_label: |
| 1793 | while self._is_clone_of is not None: |
| 1794 | self = self._is_clone_of |
| 1795 | |
| 1796 | # as of 1.4 anonymous label for ColumnElement uses hash(), not id(), |
| 1797 | # as the identifier, because a column and its annotated version are |
| 1798 | # the same thing in a SQL statement |
| 1799 | hash_value = hash(self) |
| 1800 | |
| 1801 | if add_hash: |
| 1802 | # this path is used for disambiguating anon labels that would |
| 1803 | # otherwise be the same name for the same element repeated. |
| 1804 | # an additional numeric value is factored in for each label. |
| 1805 | |
| 1806 | # shift hash(self) (which is id(self), typically 8 byte integer) |
| 1807 | # 16 bits leftward. fill extra add_hash on right |
| 1808 | assert add_hash < (2 << 15) |
| 1809 | assert seed |
| 1810 | hash_value = (hash_value << 16) | add_hash |
| 1811 | |
| 1812 | # extra underscore is added for labels with extra hash |
| 1813 | # values, to isolate the "deduped anon" namespace from the |
| 1814 | # regular namespace. eliminates chance of these |
| 1815 | # manufactured hash values overlapping with regular ones for some |
| 1816 | # undefined python interpreter |
| 1817 | seed = seed + "_" |
| 1818 | |
| 1819 | if isinstance(seed, _anonymous_label): |
| 1820 | # NOTE: the space after the hash is required |
| 1821 | return _anonymous_label(f"{seed}%({hash_value} )s") |
| 1822 | |
| 1823 | return _anonymous_label.safe_construct(hash_value, seed or "anon") |
| 1824 | |
| 1825 | @util.memoized_property |
| 1826 | def _anon_name_label(self) -> str: |