{"id":23344413,"url":"https://github.com/rec/stroll","last_synced_at":"2026-01-29T10:56:03.466Z","repository":{"id":57471925,"uuid":"266531072","full_name":"rec/stroll","owner":"rec","description":"A simpler and more powerful os.walk","archived":false,"fork":false,"pushed_at":"2021-08-17T15:42:12.000Z","size":65,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-07T08:18:06.456Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rec.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGELOG","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-24T11:56:22.000Z","updated_at":"2025-11-08T08:44:13.000Z","dependencies_parsed_at":"2022-08-30T13:51:47.285Z","dependency_job_id":null,"html_url":"https://github.com/rec/stroll","commit_stats":null,"previous_names":["rec/wolk"],"tags_count":8,"template":false,"template_full_name":"rec/safer","purl":"pkg:github/rec/stroll","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rec%2Fstroll","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rec%2Fstroll/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rec%2Fstroll/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rec%2Fstroll/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rec","download_url":"https://codeload.github.com/rec/stroll/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rec%2Fstroll/sbom","scorecard":{"id":767034,"data":{"date":"2025-08-11","repo":{"name":"github.com/rec/stroll","commit":"d2d04c00eac2dae599582748d8bbc30794db2850"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-23T01:08:20.363Z","repository_id":57471925,"created_at":"2025-08-23T01:08:20.363Z","updated_at":"2025-08-23T01:08:20.363Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28876553,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-29T10:31:27.438Z","status":"ssl_error","status_checked_at":"2026-01-29T10:31:01.017Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-21T06:26:37.190Z","updated_at":"2026-01-29T10:56:03.429Z","avatar_url":"https://github.com/rec.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"🚶 stroll: a better os.path.walk 🚶\n-------------------------------------\n\n``stroll`` is a drop-in substitute for ``os.path.walk()`` with more features:\n\n* Unix-style globs or \"star notation\" like \\*.py\n\n* Walks over multiple roots\n\n* Calls expanduser to handle paths like ``~/foo.txt``\n\n* Yields ``pathlib.Path()`` instead of ``str``\n\n* Yields full absolute paths by default\n\n* Can exclude or include files flexibly by pattern or function\n\n* Raises ``FileNotFoundError`` if a root directory doesn't exist, instead\n  of silently doing nothing like ``os.walk`` does\n\n* Excludes dotfiles by default\n\n* Includes two functions for ignoring generated files in a Python project:\n\n  * The Python build, test and release cycle tend to leave generated files in\n    places like ``build/`` or ``__pycache__/``, and usually you want to ignore\n    these\n\n  * ``stroll.python_source()`` iterates over Python source files\n\n  * ``stroll.python()`` iterates over all source files in a Python project\n\n  * The files and directories that are ignored are:\n      * files or directories that start with a ``.``\n      * ``.egg-info/`` and ``__pycache__/``\n      * ``build/``, ``dist/`` and ``htmlcov/`` at the top level only\n\nAPI\n===\n\n``stroll()``\n~~~~~~~~~~~~\n\n.. code-block:: python\n\n  stroll(\n       roots='.',\n       topdown=True,\n       onerror=None,\n       followlinks=False,\n       include=None,\n       exclude=\u003cfunction dotfile at 0x10c6e47b8\u003e,\n       directories=False,\n       relative=False,\n       with_root=None,\n       sort=True,\n       suffix=None,\n       separator=',',\n       ignore_missing_roots=False,\n  )\n\n(`stroll.py, 59-228 \u003chttps://github.com/rec/stroll/blob/master/stroll.py#L59-L228\u003e`_)\n\nDirectory walker that improves on ``os.walk()``.\n\nFor each directory in ``roots``, walk through each file in each\nsubdirectory and yield a Path to that file.  Ignores dotfiles by default.\n\nEXAMPLE\n\n.. code-block:: python\n\n    import stroll\n\n    for f in stroll('~/foo:~/bar'):\n        if f.suffix == '.txt':\n            print(f)\n\n    for f in stroll.python_source('/code/project'):\n        assert f.suffix == '.py'\n\nARGUMENTS\n  roots\n    Either a list or tuple of strings, or a single string that is split\n    using ``separator`` (defaults to ``,``, the comma).\n\n  topdown (argument to ``os.walk``)\n    If optional arg ``topdown`` is true or not specified, the ``Path`` to a\n    directory is generated before any of its subdirectories - directories\n    are generated top-down.\n\n    If ``topdown`` is false, the Path to a directory is generated after all\n    of its subdirectories - directories are generated bottom up.\n\n  onerror (argument to ``os.walk``)\n    By default errors from the ``os.scandir()`` call are ignored.  If\n    optional arg ``onerror`` is specified, it should be a function; it\n    will be called with one argument, an OSError instance.  It can\n    report the error to continue with the walk, or raise the exception\n    to abort the walk.  Note that the filename is available as the\n    filename attribute of the exception object.\n\n  followlinks (argument to ``os.walk``)\n    By default, ``os.walk()`` does not follow symbolic links to\n    subdirectories on systems that support them.  In order to get this\n    functionality, set the optional argument ``followlinks`` to true.\n\n    Caution:  if you pass a relative pathname for top, don't change the\n    current working directory between resumptions of walk.  ``os.walk()``\n    never changes the current directory, and assumes that the client\n    doesn't either.\n\n  include\n    A list of patterns that files must match.\n\n    Patterns can either be a Unix-style match string,\n    or a Python callable which returns ``True`` if the file matches\n\n  exclude\n    A list of patterns that files cannot match (and will skip).\n\n    Patterns can either be a Unix-style match string,\n    or a Python callable which returns ``True`` if the file matches.\n\n  directories\n    If true, both files and directories are yielded.\n    If false, the default, only files are yielded\n\n  relative\n    If true, file paths are relative to the root they were found in.\n    If false, the default, absolute paths are generated.\n\n  with_root\n    If true, pairs looking like (root, filepath) are generated.\n    If ``False``, just file paths are generated.\n    If ``None``, the default, pairs are generated only if there is more than\n    one root *and* relative paths are selected.\n\n  sort\n    If true, files or subdirectories are generated in sorted order.\n    If false, the default, files or subdirectories are generated in\n    whatever order the operating system gives them, which might be\n    sorted anyway\n\n  suffix\n     If ``None``, the default, there is no suffix matching.  Note that\n     ``include`` and ``exclude`` might match suffixes independently.\n\n  ignore_missing_roots\n    If true, root directories that do not exist are silently skipped.\n    If false, the default, all roots are checked for existence before\n    any files are generated.\n\n``stroll.python()``\n~~~~~~~~~~~~~~~~~~~\n\n.. code-block:: python\n\n  stroll.python(\n       roots,\n       topdown=True,\n       onerror=None,\n       followlinks=False,\n       include=None,\n       exclude=(\u003cfunction dotfile at 0x10c6e47b8\u003e, \u003cfunction match_root at 0x10c754400\u003e, \u003cfunction match_suffix at 0x10c754488\u003e, \u003cfunction match at 0x10c754510\u003e),\n       directories=False,\n       relative=False,\n       with_root=None,\n       sort=True,\n       suffix=None,\n       separator=',',\n       ignore_missing_roots=False,\n  )\n\nIterate over a Python project, skipping generated files\n\n``stroll.python_source()``\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. code-block:: python\n\n  stroll.python_source(\n       roots,\n       topdown=True,\n       onerror=None,\n       followlinks=False,\n       include='*.py',\n       exclude=(\u003cfunction dotfile at 0x10c6e47b8\u003e, \u003cfunction match_root at 0x10c754400\u003e, \u003cfunction match_suffix at 0x10c754488\u003e, \u003cfunction match at 0x10c754510\u003e),\n       directories=False,\n       relative=False,\n       with_root=None,\n       sort=True,\n       suffix=None,\n       separator=',',\n       ignore_missing_roots=False,\n  )\n\nIterate over \\*.py files in a Python project, skipping generated files\n\n(automatically generated by `doks \u003chttps://github.com/rec/doks/\u003e`_ on 2020-11-21T15:09:32.268025)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frec%2Fstroll","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frec%2Fstroll","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frec%2Fstroll/lists"}