Walk the specified directory tree in deterministic order. Takes the same parameters as os.walk and yields tuples of the same shape, except for the `topdown` parameter, which must always be true. `deterministic_walk` is essentially a wrapper of os.walk, and os.walk doesn't allow modi
(*args, **kwargs)
| 518 | |
| 519 | |
| 520 | def deterministic_walk(*args, **kwargs): |
| 521 | # type: (*Any, **Any) -> Iterator[Tuple[str, List[str], List[str]]] |
| 522 | """Walk the specified directory tree in deterministic order. |
| 523 | |
| 524 | Takes the same parameters as os.walk and yields tuples of the same shape, |
| 525 | except for the `topdown` parameter, which must always be true. |
| 526 | `deterministic_walk` is essentially a wrapper of os.walk, and os.walk doesn't |
| 527 | allow modifying the order of the walk when called with `topdown` set to false. |
| 528 | |
| 529 | os.walk uses os.listdir or os.scandir, depending on the Python version, |
| 530 | both of which don't guarantee the order in which directory entries get listed. |
| 531 | So when the build output depends on the order of directory traversal, |
| 532 | use deterministic_walk instead. |
| 533 | """ |
| 534 | # when topdown is false, modifying ``dirs`` has no effect |
| 535 | assert kwargs.get("topdown", True), "Determinism cannot be guaranteed when ``topdown`` is false" |
| 536 | for root, dirs, files in os.walk(*args, **kwargs): |
| 537 | dirs.sort() |
| 538 | files.sort() |
| 539 | yield root, dirs, files |
| 540 | # make sure ``dirs`` is sorted after any modifications |
| 541 | dirs.sort() |
| 542 | |
| 543 | |
| 544 | @contextlib.contextmanager |