Remove a node pack from custom_nodes. On Windows, file locks (antivirus, git handles) can prevent immediate deletion. Strategy: retry rmtree, then fall back to rename (moves the directory out of the resolver's scan path so stale deps don't leak).
(name: str)
| 157 | |
| 158 | |
| 159 | def _remove_pack(name: str) -> None: |
| 160 | """Remove a node pack from custom_nodes. |
| 161 | |
| 162 | On Windows, file locks (antivirus, git handles) can prevent immediate |
| 163 | deletion. Strategy: retry rmtree, then fall back to rename (moves the |
| 164 | directory out of the resolver's scan path so stale deps don't leak). |
| 165 | """ |
| 166 | path = os.path.join(CUSTOM_NODES, name) |
| 167 | if os.path.islink(path): |
| 168 | os.unlink(path) |
| 169 | return |
| 170 | if not os.path.isdir(path): |
| 171 | return |
| 172 | for attempt in range(3): |
| 173 | try: |
| 174 | shutil.rmtree(path) |
| 175 | return |
| 176 | except OSError: |
| 177 | if attempt < 2: |
| 178 | time.sleep(1) |
| 179 | # Fallback: rename out of custom_nodes so resolver won't scan it |
| 180 | import uuid |
| 181 | trash = os.path.join(CUSTOM_NODES, f".trash_{uuid.uuid4().hex[:8]}") |
| 182 | try: |
| 183 | os.rename(path, trash) |
| 184 | shutil.rmtree(trash, ignore_errors=True) |
| 185 | except OSError: |
| 186 | shutil.rmtree(path, ignore_errors=True) |
| 187 | |
| 188 | |
| 189 | def _pack_exists(name: str) -> bool: |
no outgoing calls
no test coverage detected