octopolars


Nameoctopolars JSON
Version 1.1.4 PyPI version JSON
download
home_pageNone
SummaryPull, filter, walk, and read a GitHub user's repositories with Polars.
upload_time2025-02-20 21:05:30
maintainerNone
docs_urlNone
authorNone
requires_python>=3.11
licenseMIT
keywords fsspec github polars repositories
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # octopolars

<!-- [![downloads](https://static.pepy.tech/badge/octopolars/month)](https://pepy.tech/project/octopolars) -->
[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
[![pdm-managed](https://img.shields.io/badge/pdm-managed-blueviolet)](https://pdm.fming.dev)
[![PyPI](https://img.shields.io/pypi/v/octopolars.svg)](https://pypi.org/project/octopolars)
[![Supported Python versions](https://img.shields.io/pypi/pyversions/octopolars.svg)](https://pypi.org/project/octopolars)
[![License](https://img.shields.io/pypi/l/octopolars.svg)](https://pypi.python.org/pypi/octopolars)
[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/lmmx/octopolars/master.svg)](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<!-- [![downloads](https://static.pepy.tech/badge/octopolars/month)](https://pepy.tech/project/octopolars) -->\n[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)\n[![pdm-managed](https://img.shields.io/badge/pdm-managed-blueviolet)](https://pdm.fming.dev)\n[![PyPI](https://img.shields.io/pypi/v/octopolars.svg)](https://pypi.org/project/octopolars)\n[![Supported Python versions](https://img.shields.io/pypi/pyversions/octopolars.svg)](https://pypi.org/project/octopolars)\n[![License](https://img.shields.io/pypi/l/octopolars.svg)](https://pypi.python.org/pypi/octopolars)\n[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/lmmx/octopolars/master.svg)](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"
}
        
Elapsed time: 0.43302s