Name | octopolars JSON |
Version |
1.1.4
JSON |
| download |
home_page | None |
Summary | Pull, filter, walk, and read a GitHub user's repositories with Polars. |
upload_time | 2025-02-20 21:05:30 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.11 |
license | MIT |
keywords |
fsspec
github
polars
repositories
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# octopolars
<!-- [](https://pepy.tech/project/octopolars) -->
[](https://github.com/astral-sh/uv)
[](https://pdm.fming.dev)
[](https://pypi.org/project/octopolars)
[](https://pypi.org/project/octopolars)
[](https://pypi.python.org/pypi/octopolars)
[](https://results.pre-commit.ci/latest/github/lmmx/octopolars/master)
Pull, filter, walk, and read a GitHub user's repositories with Polars.
## Installation
```bash
pip install octopolars
```
> The `polars` dependency is required but not included in the package by default.
> It is shipped as an optional extra which can be activated by passing it in square brackets:
> ```bash
> pip install octopolars[polars] # most users can install regular Polars
> pip install octopolars[polars-lts-cpu] # for backcompatibility with older CPUs
> ```
### Requirements
- Python 3.9+
- [gh](https://cli.github.com/) GitHub CLI tool, for a [PAT](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)
to avoid rate limits and enable file listings.
- **alternatively** set the `GH_TOKEN` environment variable as your GitHub token.
octopolars is supported by:
- [Polars](https://www.pola.rs/) for efficient data filtering and output formatting.
- [PyGithub](https://github.com/PyGithub/PyGithub) (for GitHub API access to enumerate the repos)
- [fsspec](https://github.com/fsspec/filesystem_spec) within [Universal Pathlib](https://github.com/fsspec/universal_pathlib)
which provides a `github://` protocol that enables enumerating files in GitHub repos as if they were local file paths.
## Features
- **GitHub repo enumeration**: Retrieve user’s public repos (caching results to speed up repeated calls).
- **Apply filters**: Use either raw Polars expressions or a shorthand DSL (e.g. `{name}.str.starts_with("foo")`) to filter repos.
- **File tree walking**: Enumerate all files in each repository using `fsspec[github]`, supporting recursion and optional size filters.
- **Output formats**: Display data in a Polars repr table (which can be [read back in](https://docs.pola.rs/api/python/stable/reference/api/polars.from_repr.html))
or export to CSV/JSON/NDJSON.
- **Control table size**: Limit the number of rows or columns displayed, or use `--quiet` mode to quickly preview data.
- **Caching**: By default, results are cached in the user’s cache directory to avoid repeated API calls (unless you force refresh).
## Usage
### Command-Line Interface
There are 2 subcommands, `repos` and `issues`.
```sh
$ octopols --help
Usage: octopols [OPTIONS] COMMAND [ARGS]...
GitHub CLI with 2 subcommands (see their help text for more information).
If no subcommand is given, the `repos` command is called by default.
Options:
--help Show this message and exit.
Commands:
issues List issues for the given GitHub username.
repos Octopols - A CLI for listing GitHub repos or files by username,...
```
The `repos` one is the default subcommand, and will run with just the `octopols` command plus a username.
### octopols repos
```bash
Usage: octopols [OPTIONS] USERNAME
Octopols - A CLI for listing GitHub repos or files by username, with
filters.
By default, this prints a table of repositories.
The --walk/-w flag walks the files rather than just listing the repos.
The --extract/-x flag reads all matching files (use with caution).
The --filter/-f flag (1+ times) applies `filter` exprs, or f-string-like
column DSL (e.g., '{name}.str.starts_with("a")').
The --select/-s flag (1+ times) applies `select` exprs, or f-string-like
column DSL (e.g., '{foo}.alias("bar")').
The --addcols/-a flag (1+ times) applies `with_columns` exprs, or
f-string-like column DSL (e.g., '{total} * 2').
The --quiet/-q flag switches to a minimal, abridged view. By default, rows
and cols are unlimited (-1).
Examples
--------
- List all repos
octopols lmmx
- List all repos that start with 'd'
octopols lmmx -f '{name}.str.starts_with("d")'
- List only file paths from matching repos
octopols lmmx -w -f '{name} == "myrepo"'
- Read the *content* of all files from matching repos
octopols lmmx -x -f '{name}.str.starts_with("d3")'
- Filter and sort the repos by stars
octopols lmmx -f '{stars} > 8' -s 'pl.all().sort_by("stars",
descending=True)'
Options:
-w, --walk Walk files (default lists repos).
-x, --extract Read the text content of each file (not
directories). Use with caution on large sets!
-o, --output-format TEXT Output format: table, csv, json, or ndjson.
-c, --cols INTEGER Number of table columns to show. Default -1 means
show all.
-r, --rows INTEGER Number of table rows to show. Default -1 means
show all.
-q, --quiet Quiet mode: overrides --rows and --cols by setting
both to None.
-f, --filter TEXT One or more Polars expressions or a shorthand DSL
expression. In the DSL, use {column} to refer to
pl.col('column'), e.g.
'{name}.str.starts_with("a")'.
-s, --select TEXT One or more Polars expressions or a shorthand DSL
expression. In the DSL, use {column} to refer to
pl.col('column'), e.g. '{foo}.alias("bar")'.
-a, --addcols TEXT One or more Polars expressions or a shorthand DSL
expression. In the DSL, use {column} to refer to
pl.col('column'), e.g. '{total} * 2'.
--help Show this message and exit.
```
#### Example 1: List All Repos for a User
```bash
octopols lmmx --quiet
```
Displays a table of all repositories belonging to "lmmx" in abridged format.
```
shape: (226, 9)
┌────────────────────────┬────────────────┬─────────────────────────────────┬──────────┬───┬────────┬───────┬───────┬───────┐
│ name ┆ default_branch ┆ description ┆ archived ┆ … ┆ issues ┆ stars ┆ forks ┆ size │
│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ str ┆ str ┆ bool ┆ ┆ i64 ┆ i64 ┆ i64 ┆ i64 │
╞════════════════════════╪════════════════╪═════════════════════════════════╪══════════╪═══╪════════╪═══════╪═══════╪═══════╡
│ 2020-viz ┆ master ┆ ┆ false ┆ … ┆ 10 ┆ 0 ┆ 0 ┆ 1459 │
│ 3dv ┆ master ┆ Some 3D file handling with num… ┆ false ┆ … ┆ 0 ┆ 0 ┆ 0 ┆ 21096 │
│ AbbrevJ ┆ master ┆ JS journal abbreviation genera… ┆ true ┆ … ┆ 0 ┆ 0 ┆ 0 ┆ 724 │
│ AdaBins ┆ main ┆ Official implementation of Ada… ┆ false ┆ … ┆ 0 ┆ 1 ┆ 0 ┆ 560 │
│ advent-of-code-2017 ┆ master ┆ Advent of Code 2017 ┆ true ┆ … ┆ 0 ┆ 0 ┆ 0 ┆ 32 │
│ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … │
│ whisper ┆ main ┆ ┆ false ┆ … ┆ 0 ┆ 1 ┆ 0 ┆ 3118 │
│ wikitransp ┆ master ┆ Dataset of transparent images … ┆ false ┆ … ┆ 3 ┆ 0 ┆ 0 ┆ 58 │
│ wotd ┆ master ┆ Analysis of WOTD data from Twe… ┆ false ┆ … ┆ 1 ┆ 1 ┆ 0 ┆ 92 │
│ wwdc-21-3d-obj-capture ┆ master ┆ "TakingPicturesFor3DObjectCapt… ┆ false ┆ … ┆ 1 ┆ 1 ┆ 0 ┆ 2861 │
│ YouCompleteMe ┆ master ┆ A code-completion engine for V… ┆ false ┆ … ┆ 0 ┆ 1 ┆ 0 ┆ 32967 │
└────────────────────────┴────────────────┴─────────────────────────────────┴──────────┴───┴────────┴───────┴───────┴───────┘
```
#### Example 2: Filter Repos by Name
```bash
octopols lmmx -f '{name}.str.contains("demo")'
```
Uses the DSL expression to select only repositories with “demo” in the repo name.
```
shape: (9, 9)
┌──────────────────────────────┬────────────────┬─────────────────────────────────┬──────────┬─────────┬────────┬───────┬───────┬───────┐
│ name ┆ default_branch ┆ description ┆ archived ┆ is_fork ┆ issues ┆ stars ┆ forks ┆ size │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ str ┆ str ┆ bool ┆ bool ┆ i64 ┆ i64 ┆ i64 ┆ i64 │
╞══════════════════════════════╪════════════════╪═════════════════════════════════╪══════════╪═════════╪════════╪═══════╪═══════╪═══════╡
│ aiohttp-demos ┆ master ┆ Demos for aiohttp project ┆ false ┆ true ┆ 0 ┆ 0 ┆ 0 ┆ 45445 │
│ demopyrs ┆ master ┆ Demo Python/Rust extension lib… ┆ false ┆ false ┆ 0 ┆ 0 ┆ 0 ┆ 18 │
│ importstring_demo ┆ master ┆ Demo of deptry inability to de… ┆ false ┆ false ┆ 0 ┆ 1 ┆ 0 ┆ 7 │
│ pyd2ts-demo ┆ master ┆ Demo of a Pydantic model conve… ┆ false ┆ false ┆ 0 ┆ 0 ┆ 0 ┆ 761 │
│ react-htmx-demo ┆ master ┆ Demo app combining HTMX and Re… ┆ false ┆ false ┆ 0 ┆ 0 ┆ 0 ┆ 2 │
│ self-serve-demo ┆ master ┆ Python package auto-generated … ┆ false ┆ false ┆ 1 ┆ 1 ┆ 0 ┆ 14 │
│ sphinx-type-annotations-demo ┆ master ┆ [Resolved] A demo of how to bu… ┆ false ┆ false ┆ 1 ┆ 0 ┆ 0 ┆ 39 │
│ uv-doc-url-demo ┆ master ┆ Proof-of-concept for extractin… ┆ false ┆ false ┆ 0 ┆ 0 ┆ 0 ┆ 27 │
│ uv-ws-demo ┆ master ┆ A simple demo of the new works… ┆ false ┆ false ┆ 0 ┆ 1 ┆ 0 ┆ 15 │
└──────────────────────────────┴────────────────┴─────────────────────────────────┴──────────┴─────────┴────────┴───────┴───────┴───────┘
```
#### Example 3: Walk an Entire Repo
```bash
octopols lmmx -f '{name} == "mvdef"' --walk --quiet
```
Lists all files in the repository named "mvdef", abbreviating the output table in 'quiet' format.
```
shape: (121, 4)
┌─────────────────┬─────────────────────────────────┬──────────────┬─────────────────┐
│ repository_name ┆ file_path ┆ is_directory ┆ file_size_bytes │
│ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ str ┆ bool ┆ i64 │
╞═════════════════╪═════════════════════════════════╪══════════════╪═════════════════╡
│ mvdef ┆ .github ┆ true ┆ 0 │
│ mvdef ┆ .github/CONTRIBUTING.md ┆ false ┆ 3094 │
│ mvdef ┆ .github/workflows ┆ true ┆ 0 │
│ mvdef ┆ .github/workflows/master.yml ┆ false ┆ 3398 │
│ mvdef ┆ .gitignore ┆ false ┆ 204 │
│ … ┆ … ┆ … ┆ … │
│ mvdef ┆ tools ┆ true ┆ 0 │
│ mvdef ┆ tools/github ┆ true ┆ 0 │
│ mvdef ┆ tools/github/install_miniconda… ┆ false ┆ 353 │
│ mvdef ┆ tox.ini ┆ false ┆ 1251 │
│ mvdef ┆ vercel.json ┆ false ┆ 133 │
└─────────────────┴─────────────────────────────────┴──────────────┴─────────────────┘
```
#### Example 4: Filter Repos by Name, List All Files
```bash
octopols lmmx -f '{name}.str.starts_with("d3")' --walk
```
List all files in every repository owned by "lmmx" whose repo name starts with "d3".
```
shape: (12, 4)
┌────────────────────┬───────────────────────────────┬──────────────┬─────────────────┐
│ repository_name ┆ file_path ┆ is_directory ┆ file_size_bytes │
│ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ str ┆ bool ┆ i64 │
╞════════════════════╪═══════════════════════════════╪══════════════╪═════════════════╡
│ d3-step-functions ┆ README.md ┆ false ┆ 62 │
│ d3-step-functions ┆ d3-step-function-diagram.html ┆ false ┆ 498 │
│ d3-step-functions ┆ d3.v7.min.js ┆ false ┆ 278580 │
│ d3-step-functions ┆ wd-style.css ┆ false ┆ 35 │
│ d3-step-functions ┆ wd_sample_data.json ┆ false ┆ 1053 │
│ d3-step-functions ┆ wiring-diagram.js ┆ false ┆ 9264 │
│ d3-wiring-diagrams ┆ README.md ┆ false ┆ 66 │
│ d3-wiring-diagrams ┆ d3-wiring-diagram.html ┆ false ┆ 484 │
│ d3-wiring-diagrams ┆ d3.v7.min.js ┆ false ┆ 278580 │
│ d3-wiring-diagrams ┆ wd-style.css ┆ false ┆ 35 │
│ d3-wiring-diagrams ┆ wd_sample_data.json ┆ false ┆ 1053 │
│ d3-wiring-diagrams ┆ wiring-diagram.js ┆ false ┆ 7482 │
└────────────────────┴───────────────────────────────┴──────────────┴─────────────────┘
```
#### Example 5: Filter Repos by Name, Read All Files
```bash
octopols lmmx -x --filter='{name}.str.contains("uv")' --quiet
```
Read the content of all files whose repo name starts with "d3" owned by "lmmx".
```
shape: (28, 4)
┌─────────────────┬────────────────────────────┬─────────────────┬─────────────────────────────────┐
│ repository_name ┆ file_path ┆ file_size_bytes ┆ content │
│ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ str ┆ i64 ┆ str │
╞═════════════════╪════════════════════════════╪═════════════════╪═════════════════════════════════╡
│ uv-doc-url-demo ┆ .gitignore ┆ 8 ┆ /target │
│ ┆ ┆ ┆ │
│ uv-doc-url-demo ┆ Cargo.lock ┆ 90700 ┆ # This file is automatically @… │
│ uv-doc-url-demo ┆ Cargo.toml ┆ 632 ┆ [package] │
│ ┆ ┆ ┆ name = "uv-doc-url-d… │
│ uv-doc-url-demo ┆ README.md ┆ 2361 ┆ # uv-doc-url-demo │
│ ┆ ┆ ┆ │
│ ┆ ┆ ┆ A Rust proo… │
│ uv-doc-url-demo ┆ src ┆ 0 ┆ │
│ … ┆ … ┆ … ┆ … │
│ uv-ws-demo ┆ src ┆ 0 ┆ │
│ uv-ws-demo ┆ src/workspaces ┆ 0 ┆ │
│ uv-ws-demo ┆ src/workspaces/__init__.py ┆ 45 ┆ from .cli import greet │
│ ┆ ┆ ┆ │
│ ┆ ┆ ┆ __all_… │
│ uv-ws-demo ┆ src/workspaces/cli.py ┆ 461 ┆ from sys import argv │
│ ┆ ┆ ┆ │
│ ┆ ┆ ┆ from pyd… │
│ uv-ws-demo ┆ uv.lock ┆ 19814 ┆ version = 1 │
│ ┆ ┆ ┆ requires-python = … │
└─────────────────┴────────────────────────────┴─────────────────┴─────────────────────────────────┘
```
#### Example 6: Filter Repos by Name, Add Columns Based on Description
```bash
octopols lmmx -f '{name}.str.starts_with("d3")' -a '{description}.str.contains("AWS").alias("Will It Cloud?")'
```
Adds a boolean column called "Will It Cloud?" based on whether the repo description contains "AWS".
```
shape: (2, 10)
┌────────────────────┬────────────────┬─────────────────────────────────┬──────────┬─────────┬────────┬───────┬───────┬──────┬────────────────┐
│ name ┆ default_branch ┆ description ┆ archived ┆ is_fork ┆ issues ┆ stars ┆ forks ┆ size ┆ Will It Cloud? │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ str ┆ str ┆ bool ┆ bool ┆ i64 ┆ i64 ┆ i64 ┆ i64 ┆ bool │
╞════════════════════╪════════════════╪═════════════════════════════════╪══════════╪═════════╪════════╪═══════╪═══════╪══════╪════════════════╡
│ d3-step-functions ┆ master ┆ AWS Step Function visualisatio… ┆ false ┆ false ┆ 1 ┆ 1 ┆ 0 ┆ 94 ┆ true │
│ d3-wiring-diagrams ┆ master ┆ Wiring diagram operad visualis… ┆ false ┆ false ┆ 2 ┆ 2 ┆ 0 ┆ 111 ┆ false │
└────────────────────┴────────────────┴─────────────────────────────────┴──────────┴─────────┴────────┴───────┴───────┴──────┴────────────────┘
```
#### Example 7: Filter Repos by Stars, Sort By Stars
```sh
octopols lmmx -f '{stars} > 8' -s 'pl.all().sort_by("stars", descending=True)'
```
```
shape: (6, 9)
┌──────────────────────────┬────────────────┬─────────────────────────────────┬──────────┬─────────┬────────┬───────┬───────┬───────┐
│ name ┆ default_branch ┆ description ┆ archived ┆ is_fork ┆ issues ┆ stars ┆ forks ┆ size │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ str ┆ str ┆ bool ┆ bool ┆ i64 ┆ i64 ┆ i64 ┆ i64 │
╞══════════════════════════╪════════════════╪═════════════════════════════════╪══════════╪═════════╪════════╪═══════╪═══════╪═══════╡
│ gdocs2md-html ┆ master ┆ Convert a Google Drive Documen… ┆ true ┆ false ┆ 12 ┆ 289 ┆ 37 ┆ 92 │
│ page-dewarp ┆ master ┆ Document image dewarping libra… ┆ false ┆ false ┆ 8 ┆ 138 ┆ 20 ┆ 11171 │
│ deforum-stable-diffusion ┆ master ┆ Refactor of the Deforum Stable… ┆ false ┆ false ┆ 6 ┆ 105 ┆ 17 ┆ 68 │
│ devnotes ┆ master ┆ obscure technical resolutions … ┆ false ┆ false ┆ 1 ┆ 89 ┆ 7 ┆ 6122 │
│ tabsave ┆ master ┆ Super simple Chrome extension … ┆ false ┆ false ┆ 20 ┆ 64 ┆ 21 ┆ 1020 │
│ range-streams ┆ master ┆ Streaming range requests in Py… ┆ false ┆ false ┆ 10 ┆ 9 ┆ 0 ┆ 402 │
└──────────────────────────┴────────────────┴─────────────────────────────────┴──────────┴─────────┴────────┴───────┴───────┴───────┘
```
### octopols issues
The issues is an extra feature, and paginates 100 issues at a time (anything above that
may make you wait a little while).
```sh
time octopols issues huggingface/transformers > /dev/null
```
```
Listing issues for user: huggingface, repo: transformers
real 0m24.350s
user 0m3.148s
sys 0m0.195s
```
Some more example usage follows.
### Example 1: Sort issues by frequency of a keyword
```sh
octopols issues pola-rs/polars -a '{body}.str.count_matches("foo").alias("matches")' -s 'pl.all().sort_by({matches}, descending=True)' -s 'pl.col("number", "title", "body")' -f '{matches} > 0' -o json
```
This one could be used interactively with `jq` to pretty-print the JSON output, or in a CI workflow.
It says:
- List all the issues on the pola-rs/polars repo
- Add a "matches" column made from the count of the string "foo" in the "body" column
- Sort the rows by the matches column
- Select just the columns "number", "title", "body"
- Filter to rows with at least one match
- Write as JSON to STDOUT
### Library Usage
You can also import `octopols.Inventory` directly:
```python
from octopols import Inventory
inv = Inventory(username="lmmx")
repos_df = inv.list_repos()
```
If you want to apply a filter expression programmatically and walk the file trees:
```python
import polars as pl
inv = Inventory(username="lmmx", filter_exprs=[pl.col("name").str.contains("demo")])
files_df = inv.walk_file_trees()
```
## Project Structure
- `cli.py`: Defines the CLI (`octopols`) with all available options and flags.
- `inventory.py`: Core logic for retrieving repos, walking file trees, caching, and applying filters.
## Contributing
Maintained by [lmmx](https://github.com/lmmx). Contributions welcome!
1. **Issues & Discussions**: Please open a GitHub issue or discussion for bugs, feature requests, or questions.
2. **Pull Requests**: PRs are welcome!
- Install the dev extra (e.g. with [uv](https://docs.astral.sh/uv/): `uv pip install -e .[dev]`)
- Run tests (when available) and include updates to docs or examples if relevant.
- If reporting a bug, please include the version and the error message/traceback if available.
## License
This project is licensed under the [MIT License](https://opensource.org/licenses/MIT).
Raw data
{
"_id": null,
"home_page": null,
"name": "octopolars",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.11",
"maintainer_email": null,
"keywords": "fsspec, github, polars, repositories",
"author": null,
"author_email": "Louis Maddox <louismmx@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/7d/38/c0b5618d21b8cba50e06df2de096105881385b7947103d7d78de396e4011/octopolars-1.1.4.tar.gz",
"platform": null,
"description": "# octopolars\n\n<!-- [](https://pepy.tech/project/octopolars) -->\n[](https://github.com/astral-sh/uv)\n[](https://pdm.fming.dev)\n[](https://pypi.org/project/octopolars)\n[](https://pypi.org/project/octopolars)\n[](https://pypi.python.org/pypi/octopolars)\n[](https://results.pre-commit.ci/latest/github/lmmx/octopolars/master)\n\nPull, filter, walk, and read a GitHub user's repositories with Polars.\n\n## Installation\n\n```bash\npip install octopolars\n```\n\n> The `polars` dependency is required but not included in the package by default.\n> It is shipped as an optional extra which can be activated by passing it in square brackets:\n> ```bash\n> pip install octopolars[polars] # most users can install regular Polars\n> pip install octopolars[polars-lts-cpu] # for backcompatibility with older CPUs\n> ```\n\n### Requirements\n\n- Python 3.9+\n- [gh](https://cli.github.com/) GitHub CLI tool, for a [PAT](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)\n to avoid rate limits and enable file listings.\n - **alternatively** set the `GH_TOKEN` environment variable as your GitHub token.\n\noctopolars is supported by:\n\n- [Polars](https://www.pola.rs/) for efficient data filtering and output formatting.\n- [PyGithub](https://github.com/PyGithub/PyGithub) (for GitHub API access to enumerate the repos)\n- [fsspec](https://github.com/fsspec/filesystem_spec) within [Universal Pathlib](https://github.com/fsspec/universal_pathlib)\n which provides a `github://` protocol that enables enumerating files in GitHub repos as if they were local file paths.\n\n## Features\n\n- **GitHub repo enumeration**: Retrieve user\u2019s public repos (caching results to speed up repeated calls).\n- **Apply filters**: Use either raw Polars expressions or a shorthand DSL (e.g. `{name}.str.starts_with(\"foo\")`) to filter repos.\n- **File tree walking**: Enumerate all files in each repository using `fsspec[github]`, supporting recursion and optional size filters.\n- **Output formats**: Display data in a Polars repr table (which can be [read back in](https://docs.pola.rs/api/python/stable/reference/api/polars.from_repr.html))\n or export to CSV/JSON/NDJSON.\n- **Control table size**: Limit the number of rows or columns displayed, or use `--quiet` mode to quickly preview data.\n- **Caching**: By default, results are cached in the user\u2019s cache directory to avoid repeated API calls (unless you force refresh).\n\n## Usage\n\n### Command-Line Interface\n\nThere are 2 subcommands, `repos` and `issues`.\n\n```sh\n$ octopols --help\nUsage: octopols [OPTIONS] COMMAND [ARGS]...\n\n GitHub CLI with 2 subcommands (see their help text for more information).\n\n If no subcommand is given, the `repos` command is called by default.\n\nOptions:\n --help Show this message and exit.\n\nCommands:\n issues List issues for the given GitHub username.\n repos Octopols - A CLI for listing GitHub repos or files by username,...\n```\n\nThe `repos` one is the default subcommand, and will run with just the `octopols` command plus a username.\n\n### octopols repos\n\n```bash\nUsage: octopols [OPTIONS] USERNAME\n\n Octopols - A CLI for listing GitHub repos or files by username, with\n filters.\n\n By default, this prints a table of repositories.\n\n The --walk/-w flag walks the files rather than just listing the repos.\n\n The --extract/-x flag reads all matching files (use with caution).\n\n The --filter/-f flag (1+ times) applies `filter` exprs, or f-string-like\n column DSL (e.g., '{name}.str.starts_with(\"a\")').\n\n The --select/-s flag (1+ times) applies `select` exprs, or f-string-like\n column DSL (e.g., '{foo}.alias(\"bar\")').\n\n The --addcols/-a flag (1+ times) applies `with_columns` exprs, or\n f-string-like column DSL (e.g., '{total} * 2').\n\n The --quiet/-q flag switches to a minimal, abridged view. By default, rows\n and cols are unlimited (-1).\n\n Examples\n --------\n\n - List all repos\n\n octopols lmmx\n\n - List all repos that start with 'd'\n\n octopols lmmx -f '{name}.str.starts_with(\"d\")'\n\n - List only file paths from matching repos\n\n octopols lmmx -w -f '{name} == \"myrepo\"'\n\n - Read the *content* of all files from matching repos\n\n octopols lmmx -x -f '{name}.str.starts_with(\"d3\")'\n\n - Filter and sort the repos by stars\n\n octopols lmmx -f '{stars} > 8' -s 'pl.all().sort_by(\"stars\",\n descending=True)'\n\nOptions:\n -w, --walk Walk files (default lists repos).\n -x, --extract Read the text content of each file (not\n directories). Use with caution on large sets!\n -o, --output-format TEXT Output format: table, csv, json, or ndjson.\n -c, --cols INTEGER Number of table columns to show. Default -1 means\n show all.\n -r, --rows INTEGER Number of table rows to show. Default -1 means\n show all.\n -q, --quiet Quiet mode: overrides --rows and --cols by setting\n both to None.\n -f, --filter TEXT One or more Polars expressions or a shorthand DSL\n expression. In the DSL, use {column} to refer to\n pl.col('column'), e.g.\n '{name}.str.starts_with(\"a\")'.\n -s, --select TEXT One or more Polars expressions or a shorthand DSL\n expression. In the DSL, use {column} to refer to\n pl.col('column'), e.g. '{foo}.alias(\"bar\")'.\n -a, --addcols TEXT One or more Polars expressions or a shorthand DSL\n expression. In the DSL, use {column} to refer to\n pl.col('column'), e.g. '{total} * 2'.\n --help Show this message and exit.\n```\n\n#### Example 1: List All Repos for a User\n\n```bash\noctopols lmmx --quiet\n```\n\nDisplays a table of all repositories belonging to \"lmmx\" in abridged format.\n\n```\nshape: (226, 9)\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 name \u2506 default_branch \u2506 description \u2506 archived \u2506 \u2026 \u2506 issues \u2506 stars \u2506 forks \u2506 size \u2502\n\u2502 --- \u2506 --- \u2506 --- \u2506 --- \u2506 \u2506 --- \u2506 --- \u2506 --- \u2506 --- \u2502\n\u2502 str \u2506 str \u2506 str \u2506 bool \u2506 \u2506 i64 \u2506 i64 \u2506 i64 \u2506 i64 \u2502\n\u255e\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2561\n\u2502 2020-viz \u2506 master \u2506 \u2506 false \u2506 \u2026 \u2506 10 \u2506 0 \u2506 0 \u2506 1459 \u2502\n\u2502 3dv \u2506 master \u2506 Some 3D file handling with num\u2026 \u2506 false \u2506 \u2026 \u2506 0 \u2506 0 \u2506 0 \u2506 21096 \u2502\n\u2502 AbbrevJ \u2506 master \u2506 JS journal abbreviation genera\u2026 \u2506 true \u2506 \u2026 \u2506 0 \u2506 0 \u2506 0 \u2506 724 \u2502\n\u2502 AdaBins \u2506 main \u2506 Official implementation of Ada\u2026 \u2506 false \u2506 \u2026 \u2506 0 \u2506 1 \u2506 0 \u2506 560 \u2502\n\u2502 advent-of-code-2017 \u2506 master \u2506 Advent of Code 2017 \u2506 true \u2506 \u2026 \u2506 0 \u2506 0 \u2506 0 \u2506 32 \u2502\n\u2502 \u2026 \u2506 \u2026 \u2506 \u2026 \u2506 \u2026 \u2506 \u2026 \u2506 \u2026 \u2506 \u2026 \u2506 \u2026 \u2506 \u2026 \u2502\n\u2502 whisper \u2506 main \u2506 \u2506 false \u2506 \u2026 \u2506 0 \u2506 1 \u2506 0 \u2506 3118 \u2502\n\u2502 wikitransp \u2506 master \u2506 Dataset of transparent images \u2026 \u2506 false \u2506 \u2026 \u2506 3 \u2506 0 \u2506 0 \u2506 58 \u2502\n\u2502 wotd \u2506 master \u2506 Analysis of WOTD data from Twe\u2026 \u2506 false \u2506 \u2026 \u2506 1 \u2506 1 \u2506 0 \u2506 92 \u2502\n\u2502 wwdc-21-3d-obj-capture \u2506 master \u2506 \"TakingPicturesFor3DObjectCapt\u2026 \u2506 false \u2506 \u2026 \u2506 1 \u2506 1 \u2506 0 \u2506 2861 \u2502\n\u2502 YouCompleteMe \u2506 master \u2506 A code-completion engine for V\u2026 \u2506 false \u2506 \u2026 \u2506 0 \u2506 1 \u2506 0 \u2506 32967 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n#### Example 2: Filter Repos by Name\n\n```bash\noctopols lmmx -f '{name}.str.contains(\"demo\")'\n```\n\nUses the DSL expression to select only repositories with \u201cdemo\u201d in the repo name.\n\n```\nshape: (9, 9)\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 name \u2506 default_branch \u2506 description \u2506 archived \u2506 is_fork \u2506 issues \u2506 stars \u2506 forks \u2506 size \u2502\n\u2502 --- \u2506 --- \u2506 --- \u2506 --- \u2506 --- \u2506 --- \u2506 --- \u2506 --- \u2506 --- \u2502\n\u2502 str \u2506 str \u2506 str \u2506 bool \u2506 bool \u2506 i64 \u2506 i64 \u2506 i64 \u2506 i64 \u2502\n\u255e\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2561\n\u2502 aiohttp-demos \u2506 master \u2506 Demos for aiohttp project \u2506 false \u2506 true \u2506 0 \u2506 0 \u2506 0 \u2506 45445 \u2502\n\u2502 demopyrs \u2506 master \u2506 Demo Python/Rust extension lib\u2026 \u2506 false \u2506 false \u2506 0 \u2506 0 \u2506 0 \u2506 18 \u2502\n\u2502 importstring_demo \u2506 master \u2506 Demo of deptry inability to de\u2026 \u2506 false \u2506 false \u2506 0 \u2506 1 \u2506 0 \u2506 7 \u2502\n\u2502 pyd2ts-demo \u2506 master \u2506 Demo of a Pydantic model conve\u2026 \u2506 false \u2506 false \u2506 0 \u2506 0 \u2506 0 \u2506 761 \u2502\n\u2502 react-htmx-demo \u2506 master \u2506 Demo app combining HTMX and Re\u2026 \u2506 false \u2506 false \u2506 0 \u2506 0 \u2506 0 \u2506 2 \u2502\n\u2502 self-serve-demo \u2506 master \u2506 Python package auto-generated \u2026 \u2506 false \u2506 false \u2506 1 \u2506 1 \u2506 0 \u2506 14 \u2502\n\u2502 sphinx-type-annotations-demo \u2506 master \u2506 [Resolved] A demo of how to bu\u2026 \u2506 false \u2506 false \u2506 1 \u2506 0 \u2506 0 \u2506 39 \u2502\n\u2502 uv-doc-url-demo \u2506 master \u2506 Proof-of-concept for extractin\u2026 \u2506 false \u2506 false \u2506 0 \u2506 0 \u2506 0 \u2506 27 \u2502\n\u2502 uv-ws-demo \u2506 master \u2506 A simple demo of the new works\u2026 \u2506 false \u2506 false \u2506 0 \u2506 1 \u2506 0 \u2506 15 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n#### Example 3: Walk an Entire Repo\n\n```bash\noctopols lmmx -f '{name} == \"mvdef\"' --walk --quiet\n```\n\nLists all files in the repository named \"mvdef\", abbreviating the output table in 'quiet' format.\n\n```\nshape: (121, 4)\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 repository_name \u2506 file_path \u2506 is_directory \u2506 file_size_bytes \u2502\n\u2502 --- \u2506 --- \u2506 --- \u2506 --- \u2502\n\u2502 str \u2506 str \u2506 bool \u2506 i64 \u2502\n\u255e\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2561\n\u2502 mvdef \u2506 .github \u2506 true \u2506 0 \u2502\n\u2502 mvdef \u2506 .github/CONTRIBUTING.md \u2506 false \u2506 3094 \u2502\n\u2502 mvdef \u2506 .github/workflows \u2506 true \u2506 0 \u2502\n\u2502 mvdef \u2506 .github/workflows/master.yml \u2506 false \u2506 3398 \u2502\n\u2502 mvdef \u2506 .gitignore \u2506 false \u2506 204 \u2502\n\u2502 \u2026 \u2506 \u2026 \u2506 \u2026 \u2506 \u2026 \u2502\n\u2502 mvdef \u2506 tools \u2506 true \u2506 0 \u2502\n\u2502 mvdef \u2506 tools/github \u2506 true \u2506 0 \u2502\n\u2502 mvdef \u2506 tools/github/install_miniconda\u2026 \u2506 false \u2506 353 \u2502\n\u2502 mvdef \u2506 tox.ini \u2506 false \u2506 1251 \u2502\n\u2502 mvdef \u2506 vercel.json \u2506 false \u2506 133 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n#### Example 4: Filter Repos by Name, List All Files\n\n```bash\noctopols lmmx -f '{name}.str.starts_with(\"d3\")' --walk\n```\n\nList all files in every repository owned by \"lmmx\" whose repo name starts with \"d3\".\n\n```\nshape: (12, 4)\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 repository_name \u2506 file_path \u2506 is_directory \u2506 file_size_bytes \u2502\n\u2502 --- \u2506 --- \u2506 --- \u2506 --- \u2502\n\u2502 str \u2506 str \u2506 bool \u2506 i64 \u2502\n\u255e\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2561\n\u2502 d3-step-functions \u2506 README.md \u2506 false \u2506 62 \u2502\n\u2502 d3-step-functions \u2506 d3-step-function-diagram.html \u2506 false \u2506 498 \u2502\n\u2502 d3-step-functions \u2506 d3.v7.min.js \u2506 false \u2506 278580 \u2502\n\u2502 d3-step-functions \u2506 wd-style.css \u2506 false \u2506 35 \u2502\n\u2502 d3-step-functions \u2506 wd_sample_data.json \u2506 false \u2506 1053 \u2502\n\u2502 d3-step-functions \u2506 wiring-diagram.js \u2506 false \u2506 9264 \u2502\n\u2502 d3-wiring-diagrams \u2506 README.md \u2506 false \u2506 66 \u2502\n\u2502 d3-wiring-diagrams \u2506 d3-wiring-diagram.html \u2506 false \u2506 484 \u2502\n\u2502 d3-wiring-diagrams \u2506 d3.v7.min.js \u2506 false \u2506 278580 \u2502\n\u2502 d3-wiring-diagrams \u2506 wd-style.css \u2506 false \u2506 35 \u2502\n\u2502 d3-wiring-diagrams \u2506 wd_sample_data.json \u2506 false \u2506 1053 \u2502\n\u2502 d3-wiring-diagrams \u2506 wiring-diagram.js \u2506 false \u2506 7482 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n#### Example 5: Filter Repos by Name, Read All Files\n\n```bash\noctopols lmmx -x --filter='{name}.str.contains(\"uv\")' --quiet\n```\n\nRead the content of all files whose repo name starts with \"d3\" owned by \"lmmx\".\n\n```\nshape: (28, 4)\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 repository_name \u2506 file_path \u2506 file_size_bytes \u2506 content \u2502\n\u2502 --- \u2506 --- \u2506 --- \u2506 --- \u2502\n\u2502 str \u2506 str \u2506 i64 \u2506 str \u2502\n\u255e\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2561\n\u2502 uv-doc-url-demo \u2506 .gitignore \u2506 8 \u2506 /target \u2502\n\u2502 \u2506 \u2506 \u2506 \u2502\n\u2502 uv-doc-url-demo \u2506 Cargo.lock \u2506 90700 \u2506 # This file is automatically @\u2026 \u2502\n\u2502 uv-doc-url-demo \u2506 Cargo.toml \u2506 632 \u2506 [package] \u2502\n\u2502 \u2506 \u2506 \u2506 name = \"uv-doc-url-d\u2026 \u2502\n\u2502 uv-doc-url-demo \u2506 README.md \u2506 2361 \u2506 # uv-doc-url-demo \u2502\n\u2502 \u2506 \u2506 \u2506 \u2502\n\u2502 \u2506 \u2506 \u2506 A Rust proo\u2026 \u2502\n\u2502 uv-doc-url-demo \u2506 src \u2506 0 \u2506 \u2502\n\u2502 \u2026 \u2506 \u2026 \u2506 \u2026 \u2506 \u2026 \u2502\n\u2502 uv-ws-demo \u2506 src \u2506 0 \u2506 \u2502\n\u2502 uv-ws-demo \u2506 src/workspaces \u2506 0 \u2506 \u2502\n\u2502 uv-ws-demo \u2506 src/workspaces/__init__.py \u2506 45 \u2506 from .cli import greet \u2502\n\u2502 \u2506 \u2506 \u2506 \u2502\n\u2502 \u2506 \u2506 \u2506 __all_\u2026 \u2502\n\u2502 uv-ws-demo \u2506 src/workspaces/cli.py \u2506 461 \u2506 from sys import argv \u2502\n\u2502 \u2506 \u2506 \u2506 \u2502\n\u2502 \u2506 \u2506 \u2506 from pyd\u2026 \u2502\n\u2502 uv-ws-demo \u2506 uv.lock \u2506 19814 \u2506 version = 1 \u2502\n\u2502 \u2506 \u2506 \u2506 requires-python = \u2026 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n#### Example 6: Filter Repos by Name, Add Columns Based on Description\n\n```bash\noctopols lmmx -f '{name}.str.starts_with(\"d3\")' -a '{description}.str.contains(\"AWS\").alias(\"Will It Cloud?\")'\n```\n\nAdds a boolean column called \"Will It Cloud?\" based on whether the repo description contains \"AWS\".\n\n```\nshape: (2, 10)\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 name \u2506 default_branch \u2506 description \u2506 archived \u2506 is_fork \u2506 issues \u2506 stars \u2506 forks \u2506 size \u2506 Will It Cloud? \u2502\n\u2502 --- \u2506 --- \u2506 --- \u2506 --- \u2506 --- \u2506 --- \u2506 --- \u2506 --- \u2506 --- \u2506 --- \u2502\n\u2502 str \u2506 str \u2506 str \u2506 bool \u2506 bool \u2506 i64 \u2506 i64 \u2506 i64 \u2506 i64 \u2506 bool \u2502\n\u255e\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2561\n\u2502 d3-step-functions \u2506 master \u2506 AWS Step Function visualisatio\u2026 \u2506 false \u2506 false \u2506 1 \u2506 1 \u2506 0 \u2506 94 \u2506 true \u2502\n\u2502 d3-wiring-diagrams \u2506 master \u2506 Wiring diagram operad visualis\u2026 \u2506 false \u2506 false \u2506 2 \u2506 2 \u2506 0 \u2506 111 \u2506 false \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n#### Example 7: Filter Repos by Stars, Sort By Stars\n\n```sh\noctopols lmmx -f '{stars} > 8' -s 'pl.all().sort_by(\"stars\", descending=True)'\n```\n\n```\nshape: (6, 9)\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 name \u2506 default_branch \u2506 description \u2506 archived \u2506 is_fork \u2506 issues \u2506 stars \u2506 forks \u2506 size \u2502\n\u2502 --- \u2506 --- \u2506 --- \u2506 --- \u2506 --- \u2506 --- \u2506 --- \u2506 --- \u2506 --- \u2502\n\u2502 str \u2506 str \u2506 str \u2506 bool \u2506 bool \u2506 i64 \u2506 i64 \u2506 i64 \u2506 i64 \u2502\n\u255e\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2561\n\u2502 gdocs2md-html \u2506 master \u2506 Convert a Google Drive Documen\u2026 \u2506 true \u2506 false \u2506 12 \u2506 289 \u2506 37 \u2506 92 \u2502\n\u2502 page-dewarp \u2506 master \u2506 Document image dewarping libra\u2026 \u2506 false \u2506 false \u2506 8 \u2506 138 \u2506 20 \u2506 11171 \u2502\n\u2502 deforum-stable-diffusion \u2506 master \u2506 Refactor of the Deforum Stable\u2026 \u2506 false \u2506 false \u2506 6 \u2506 105 \u2506 17 \u2506 68 \u2502\n\u2502 devnotes \u2506 master \u2506 obscure technical resolutions \u2026 \u2506 false \u2506 false \u2506 1 \u2506 89 \u2506 7 \u2506 6122 \u2502\n\u2502 tabsave \u2506 master \u2506 Super simple Chrome extension \u2026 \u2506 false \u2506 false \u2506 20 \u2506 64 \u2506 21 \u2506 1020 \u2502\n\u2502 range-streams \u2506 master \u2506 Streaming range requests in Py\u2026 \u2506 false \u2506 false \u2506 10 \u2506 9 \u2506 0 \u2506 402 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n\n### octopols issues\n\nThe issues is an extra feature, and paginates 100 issues at a time (anything above that\nmay make you wait a little while).\n\n```sh\ntime octopols issues huggingface/transformers > /dev/null\n```\n\n```\nListing issues for user: huggingface, repo: transformers\n\nreal 0m24.350s\nuser 0m3.148s\nsys 0m0.195s\n```\n\nSome more example usage follows.\n\n### Example 1: Sort issues by frequency of a keyword\n\n```sh\noctopols issues pola-rs/polars -a '{body}.str.count_matches(\"foo\").alias(\"matches\")' -s 'pl.all().sort_by({matches}, descending=True)' -s 'pl.col(\"number\", \"title\", \"body\")' -f '{matches} > 0' -o json\n```\n\nThis one could be used interactively with `jq` to pretty-print the JSON output, or in a CI workflow.\n\nIt says:\n\n- List all the issues on the pola-rs/polars repo\n- Add a \"matches\" column made from the count of the string \"foo\" in the \"body\" column\n- Sort the rows by the matches column\n- Select just the columns \"number\", \"title\", \"body\"\n- Filter to rows with at least one match\n- Write as JSON to STDOUT\n\n### Library Usage\n\nYou can also import `octopols.Inventory` directly:\n\n```python\nfrom octopols import Inventory\n\ninv = Inventory(username=\"lmmx\")\nrepos_df = inv.list_repos()\n```\n\nIf you want to apply a filter expression programmatically and walk the file trees:\n\n```python\nimport polars as pl\n\ninv = Inventory(username=\"lmmx\", filter_exprs=[pl.col(\"name\").str.contains(\"demo\")])\nfiles_df = inv.walk_file_trees()\n```\n\n## Project Structure\n\n- `cli.py`: Defines the CLI (`octopols`) with all available options and flags.\n- `inventory.py`: Core logic for retrieving repos, walking file trees, caching, and applying filters.\n\n## Contributing\n\nMaintained by [lmmx](https://github.com/lmmx). Contributions welcome!\n\n1. **Issues & Discussions**: Please open a GitHub issue or discussion for bugs, feature requests, or questions.\n2. **Pull Requests**: PRs are welcome!\n - Install the dev extra (e.g. with [uv](https://docs.astral.sh/uv/): `uv pip install -e .[dev]`)\n - Run tests (when available) and include updates to docs or examples if relevant.\n - If reporting a bug, please include the version and the error message/traceback if available.\n\n## License\n\nThis project is licensed under the [MIT License](https://opensource.org/licenses/MIT).\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Pull, filter, walk, and read a GitHub user's repositories with Polars.",
"version": "1.1.4",
"project_urls": {
"Documentation": "https://octopolars.vercel.app/",
"Homepage": "https://github.com/lmmx/octopols",
"Repository": "https://github.com/lmmx/octopols.git"
},
"split_keywords": [
"fsspec",
" github",
" polars",
" repositories"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "4be32ac1a49cd02b100b636be3e2f4f76c9970740461a4fb662ca08f39d9b610",
"md5": "846b46542256f30aaeb2a36e1b09c82d",
"sha256": "75d4dea7d1c80772c0763eef3d42b82792186ef6b2623e62060800ecd548e744"
},
"downloads": -1,
"filename": "octopolars-1.1.4-py3-none-any.whl",
"has_sig": false,
"md5_digest": "846b46542256f30aaeb2a36e1b09c82d",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11",
"size": 18707,
"upload_time": "2025-02-20T21:05:29",
"upload_time_iso_8601": "2025-02-20T21:05:29.485696Z",
"url": "https://files.pythonhosted.org/packages/4b/e3/2ac1a49cd02b100b636be3e2f4f76c9970740461a4fb662ca08f39d9b610/octopolars-1.1.4-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "7d38c0b5618d21b8cba50e06df2de096105881385b7947103d7d78de396e4011",
"md5": "7ed11cbe72c5b77cee9247819e2817a3",
"sha256": "4384939483457cf1e74161a1eedd110a93d128f500116a7ea973f1ae2c1fae8a"
},
"downloads": -1,
"filename": "octopolars-1.1.4.tar.gz",
"has_sig": false,
"md5_digest": "7ed11cbe72c5b77cee9247819e2817a3",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11",
"size": 21947,
"upload_time": "2025-02-20T21:05:30",
"upload_time_iso_8601": "2025-02-20T21:05:30.931559Z",
"url": "https://files.pythonhosted.org/packages/7d/38/c0b5618d21b8cba50e06df2de096105881385b7947103d7d78de396e4011/octopolars-1.1.4.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-02-20 21:05:30",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "lmmx",
"github_project": "octopols",
"github_not_found": true,
"lcname": "octopolars"
}