From 370ce9f124e7cc51aed4c6a8688d2d10a66b3f53 Mon Sep 17 00:00:00 2001 From: juftin Date: Sat, 16 Dec 2023 15:38:38 -0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20mkdocs=20wip?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release.yaml | 59 ++--- README.md | 31 ++- docs/Makefile | 20 -- docs/README.md | 9 - docs/cli.md | 8 + docs/{source => }/contributing.md | 66 +++++- docs/gen_pages.py | 36 +++ docs/interacting.md | 72 ++++++ docs/plugins/index.md | 10 + docs/{source => plugins}/primelunch.md | 40 ++-- docs/plugins/pushlunch.md | 51 +++++ docs/plugins/splitlunch.md | 114 ++++++++++ docs/requirements.txt | 17 -- docs/source/cli.md | 7 - docs/source/cli.rst | 182 --------------- docs/source/conf.py | 102 --------- docs/source/index.rst | 83 ------- docs/source/lunchable.rst | 18 -- docs/source/plugins.rst | 14 -- docs/source/pushlunch.rst | 56 ----- docs/source/splitlunch.rst | 138 ----------- docs/source/usage.rst | 115 ---------- docs/{source/_static => static}/lunchable.png | Bin docs/usage.md | 130 +++++++++++ lunchable/models/_base.py | 14 +- lunchable/models/_core.py | 48 ++-- lunchable/models/_lunchmoney.py | 13 +- lunchable/models/assets.py | 3 +- lunchable/models/budgets.py | 15 +- lunchable/models/categories.py | 3 +- lunchable/models/crypto.py | 3 +- lunchable/models/plaid_accounts.py | 3 +- lunchable/models/recurring_expenses.py | 5 +- lunchable/models/tags.py | 3 +- lunchable/models/transactions.py | 89 +++++--- lunchable/models/user.py | 3 +- lunchable/plugins/base/base_app.py | 2 + lunchable/plugins/primelunch/primelunch.py | 8 +- .../splitlunch/lunchmoney_splitwise.py | 69 ------ mkdocs.yaml | 86 +++++++ pyproject.toml | 32 +-- requirements/requirements-docs.txt | 215 +++++++++--------- 42 files changed, 876 insertions(+), 1116 deletions(-) delete mode 100644 docs/Makefile delete mode 100644 docs/README.md create mode 100644 docs/cli.md rename docs/{source => }/contributing.md (73%) create mode 100644 docs/gen_pages.py create mode 100644 docs/interacting.md create mode 100644 docs/plugins/index.md rename docs/{source => plugins}/primelunch.md (71%) create mode 100644 docs/plugins/pushlunch.md create mode 100644 docs/plugins/splitlunch.md delete mode 100644 docs/requirements.txt delete mode 100644 docs/source/cli.md delete mode 100644 docs/source/cli.rst delete mode 100644 docs/source/conf.py delete mode 100644 docs/source/index.rst delete mode 100644 docs/source/lunchable.rst delete mode 100644 docs/source/plugins.rst delete mode 100644 docs/source/pushlunch.rst delete mode 100644 docs/source/splitlunch.rst delete mode 100644 docs/source/usage.rst rename docs/{source/_static => static}/lunchable.png (100%) create mode 100644 docs/usage.md create mode 100644 mkdocs.yaml diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index b1e017f0..bd502ae7 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -24,8 +24,9 @@ jobs: python-version: '3.11' - name: Install Hatch run: | - python -m pip install --upgrade pip + python -m pip install --upgrade pip wheel python -m pip install -q hatch pre-commit + python -m pip install -q "${{ github.workspace }}" hatch --version - name: Release run: hatch run gen:release @@ -37,60 +38,30 @@ jobs: GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com github-pages-publish: + runs-on: ubuntu-latest needs: release if: github.ref == 'refs/heads/main' && github.repository_owner == 'juftin' - runs-on: ubuntu-latest + permissions: + contents: write steps: - name: Checkout Latest Changes - uses: actions/checkout@v3 - with: - path: ${{ github.workspace }}/main - ref: ${{ github.ref }} - fetch-depth: 0 - - name: Create gh-pages if not exists - working-directory: ${{ github.workspace }}/main - run: | - git checkout gh-pages || git checkout -b gh-pages - git push --set-upstream origin gh-pages || true - git checkout main -- - - name: Checkout gh-pages Branch uses: actions/checkout@v4 with: - path: ${{ github.workspace }}/github-pages - ref: gh-pages + ref: ${{ github.ref }} fetch-depth: 0 - name: Set up Python Environment - uses: actions/setup-python@v5 + uses: actions/setup-python@v4 with: python-version: '3.11' - name: Install Hatch - working-directory: ${{ github.workspace }}/main run: | - python -m pip install --upgrade pip - python -m pip install -q hatch + python -m pip install --upgrade pip wheel + python -m pip install -q hatch pre-commit + python -m pip install -q "${{ github.workspace }}" hatch --version - - name: Documentation Generation - working-directory: ${{ github.workspace }}/main - run: | - hatch run docs:build - - name: Setup Git Config - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email "github-actions[bot]@users.noreply.github.com" - - name: Get Commit SHA from main - working-directory: ${{ github.workspace }}/main - run: | - COMMIT_SHA=$(git rev-parse HEAD) - PROJECT_VERSION=$(hatch version) - echo PROJECT_VERSION=${PROJECT_VERSION} >> $GITHUB_ENV - echo "COMMIT_SHA=${COMMIT_SHA}" >> ${GITHUB_ENV} - - name: Commit Changes to gh-pages Branch - working-directory: ${{ github.workspace }}/github-pages + - name: Set Up GitHub Actions User run: | - git rm -rf . || true - cp -R ${{ github.workspace }}/main/docs/_build/html/* ${PWD} - touch .nojekyll - cp ${{ github.workspace }}/main/docs/README.md . - git add . - git diff-index --quiet HEAD || git commit -m "GitHub Pages - ${{ env.PROJECT_VERSION }} - ${{ env.COMMIT_SHA }}" - git push origin gh-pages --force + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + - name: Deploy Documentation Changes + run: hatch run docs:gh-deploy --force diff --git a/README.md b/README.md index 4f2a1c0f..66a69ef0 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,23 @@
- lunchable
-[![Lunchable Version](https://img.shields.io/pypi/v/lunchable?color=blue&label=lunchable)](https://github.com/juftin/lunchable) -[![PyPI](https://img.shields.io/pypi/pyversions/lunchable)](https://pypi.python.org/pypi/lunchable/) -[![Docker Image Version](https://img.shields.io/docker/v/juftin/lunchable?color=blue&label=docker&logo=docker)](https://hub.docker.com/r/juftin/lunchable) -[![Testing Status](https://github.com/juftin/lunchable/actions/workflows/tests.yaml/badge.svg?branch=main)](https://github.com/juftin/lunchable/actions/workflows/tests.yaml?query=branch%3Amain) -[![GitHub License](https://img.shields.io/github/license/juftin/lunchable?color=blue&label=License)](https://github.com/juftin/lunchable/blob/main/LICENSE) +

+ PyPI + PyPI - Python Version + Docker Image Version + Testing Status + GitHub License + Hatch project + Ruff + pre-commit + semantic-release + Gitmoji +

**lunchable** is a Python Client for the [Lunch Money Developer API](https://lunchmoney.dev). It's built on top of [pydantic](https://github.com/pydantic/pydantic) and [httpx](https://github.com/encode/httpx/), @@ -27,16 +34,18 @@ pip install lunchable ### Usage ```python -from typing import Any, Dict, List +from __future__ import annotations + +from typing import Any from lunchable import LunchMoney from lunchable.models import TransactionObject lunch = LunchMoney(access_token="xxxxxxxxxxx") -transactions: List[TransactionObject] = lunch.get_transactions() +transactions: list[TransactionObject] = lunch.get_transactions() first_transaction: TransactionObject = transactions[0] -transaction_as_dict: Dict[str, Any] = first_transaction.model_dump() +transaction_as_dict: dict[str, Any] = first_transaction.model_dump() ``` ```shell @@ -45,6 +54,8 @@ lunchable transactions get --limit 5 lunchable http -X GET https://dev.lunchmoney.app/v1/assets ``` + + ### Check out the [**Docs**](https://juftin.com/lunchable/) ### Looking to contribute? See the [Contributing Guide](docs/source/contributing.md) @@ -58,3 +69,5 @@ lunchable http -X GET https://dev.lunchmoney.app/v1/assets
[

juftin logo

](https://github.com/juftin) + + diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index f016e55b..00000000 --- a/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -SPHINXPROJ = lunchable -SOURCEDIR = source -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index e2c26480..00000000 --- a/docs/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# lunchable - -A simple Python SDK around the Lunch Money Developer API - -#### This is the documentation branch of lunchable - -### [See the Documentation Website](https://juftin.github.io/lunchable) - -### [See the Latest Changes](https://github.com/juftin/lunchable) diff --git a/docs/cli.md b/docs/cli.md new file mode 100644 index 00000000..1a2932a6 --- /dev/null +++ b/docs/cli.md @@ -0,0 +1,8 @@ +# lunchable CLI + +::: mkdocs-click + :module: lunchable._cli + :command: cli + :prog_name: lunchable + :style: table + :list_subcommands: True diff --git a/docs/source/contributing.md b/docs/contributing.md similarity index 73% rename from docs/source/contributing.md rename to docs/contributing.md index 608ce697..0f03bad3 100644 --- a/docs/source/contributing.md +++ b/docs/contributing.md @@ -2,12 +2,26 @@ ## Environment Setup -1. Install [hatch](https://github.com/pypa/hatch) +> TIP: **pipx** +> +> This documentaion uses [pipx] to +> install and manage non-project command line tools like `hatch` and +> `pre-commit`. If you don't already have `pipx` installed, make sure to +> see their [documentation](https://pypa.github.io/pipx/installation/). +> If you prefer not to use `pipx`, you can use `pip` instead. + +1. Install [hatch](https://hatch.pypa.io/latest/) ```shell pipx install hatch ``` + > NOTE: **pre-commit** + > + > Hatch will attempt to set up pre-commit hooks for you using + > [pre-commit]. If you don't already, + > make sure to install pre-commit as well: `pipx install pre-commit` + 2. Build the Virtual Environment ```shell @@ -18,7 +32,7 @@ They can be located by name with the `env find` command: ```shell - hatch env find default + hatch env find test ``` 4. Activate the Virtual Environment @@ -48,6 +62,54 @@ These features include virtual environment management and the organization of co scripts like linting and testing. All the operations in hatch take place in one of its managed virtual environments. +Hatch has a variety of environments, to see them simply ask hatch: + +```bash exec="on" result="markdown" source="tabbed-left" tabs="hatch CLI|Output" +hatch env show +``` + +That above command will tell you that there are five environments that +you can use: + +- `default` +- `docs` +- `gen` +- `lint` +- `test` + +Each of these environments has a set of commands that you can run. +To see the commands for a specific environment, run: + +```bash exec="on" result="markdown" source="tabbed-left" tabs="hatch CLI|Output" +hatch env show default +``` + +Here we can see that the `default` environment has the following commands: + +- `cov` +- `test` + +The one that we're interested in is `cov`, which will run the tests +for the project. + +```bash +hatch run cov +``` + +Since `cov` is in the default environment, we can run it without +specifying the environment. However, to run the `serve` command in the +`docs` environment, we need to specify the environment: + +```bash +hatch run docs:serve +``` + +You can see what scripts are available using the `env show` command + +```bash exec="on" result="markdown" source="tabbed-left" tabs="hatch CLI|Output" +hatch env show docs +``` + ## Committing Code This project uses [pre-commit] to run a set of diff --git a/docs/gen_pages.py b/docs/gen_pages.py new file mode 100644 index 00000000..af987f26 --- /dev/null +++ b/docs/gen_pages.py @@ -0,0 +1,36 @@ +""" +Generate the code reference pages and navigation. +""" + +import logging +from pathlib import Path + +import mkdocs_gen_files + +logger = logging.getLogger(__name__) + +project_dir = Path(__file__).resolve().parent.parent +source_code = project_dir.joinpath("lunchable") + +for path in sorted(source_code.rglob("*.py")): + module_path = path.relative_to(project_dir).with_suffix("") + doc_path = path.relative_to(source_code).with_suffix(".md") + full_doc_path = Path("reference", doc_path) + + parts = tuple(module_path.parts) + if parts[-1] == "__init__": + parts = parts[:-1] + doc_path = doc_path.with_name("index.md") + full_doc_path = full_doc_path.with_name("index.md") + elif parts[-1] == "__main__": + continue + with mkdocs_gen_files.open(full_doc_path, "w") as fd: + fd.write(f"# `{parts[-1]}`\n\n::: {'.'.join(parts)}") + + mkdocs_gen_files.set_edit_path(full_doc_path, path) + +# Exclude parts that are between two exact `` lines +readme_content = Path("README.md").read_text() +readme_content = "\n".join(readme_content.split("\n\n")[::2]) +with mkdocs_gen_files.open("index.md", "w") as index_file: + index_file.write(readme_content) diff --git a/docs/interacting.md b/docs/interacting.md new file mode 100644 index 00000000..16be2216 --- /dev/null +++ b/docs/interacting.md @@ -0,0 +1,72 @@ +# LunchMoney + +The `LunchMoney` client is the main entrypoint for interacting with the Lunch Money API. +It defaults to inheriting the `LUNCHMONEY_ACCESS_TOKEN` environment variable, but can be +created with an explicit `access_token` parameter. + +```python +from lunchable import LunchMoney + +lunch = LunchMoney(access_token="xxxxxxxxxxx") +``` + +## Methods + +| HTTP Verb | Name | Description | +|-----------|--------------------------------------------------------------------------------|--------------------------------------------------------------------------| +| GET | [get_assets](#lunchable.LunchMoney.get_assets) | Get Manually Managed Assets | +| GET | [get_budgets](#lunchable.LunchMoney.get_budgets) | Get Monthly Budgets | +| GET | [get_categories](#lunchable.LunchMoney.get_categories) | Get Spending categories | +| GET | [get_category](#lunchable.LunchMoney.get_category) | Get single category | +| GET | [get_crypto](#lunchable.LunchMoney.get_crypto) | Get Crypto Assets | +| GET | [get_plaid_accounts](#lunchable.LunchMoney.get_plaid_accounts) | Get Plaid Synced Assets | +| GET | [get_recurring_expenses](#lunchable.LunchMoney.get_recurring_expenses) | Get Recurring Expenses | +| GET | [get_tags](#lunchable.LunchMoney.get_tags) | Get Spending Tags | +| GET | [get_transaction](#lunchable.LunchMoney.get_transaction) | Get a Transaction by ID | +| GET | [get_transactions](#lunchable.LunchMoney.get_transactions) | Get Transactions Using Criteria | +| GET | [get_user](#lunchable.LunchMoney.get_user) | Get Personal User Details | +| POST | [insert_asset](#lunchable.LunchMoney.insert_asset) | Create a single (manually-managed) asset | +| POST | [insert_category](#lunchable.LunchMoney.insert_category) | Create a Spending Category | +| POST | [insert_category_group](#lunchable.LunchMoney.insert_category_group) | Create a Spending Category Group | +| POST | [insert_into_category_group](#lunchable.LunchMoney.insert_into_category_group) | Add to a Category Group | +| POST | [insert_transaction_group](#lunchable.LunchMoney.insert_transaction_group) | Create a Transaction Group of Two or More Transactions | +| POST | [insert_transactions](#lunchable.LunchMoney.insert_transactions) | Create One or Many Lunch Money Transactions | +| POST | [unsplit_transactions](#lunchable.LunchMoney.unsplit_transactions) | Unsplit Transactions | +| PUT | [upsert_budget](#lunchable.LunchMoney.upsert_budget) | Upsert a Budget for a Category and Date | +| PUT | [update_asset](#lunchable.LunchMoney.update_asset) | Update a Single Asset | +| PUT | [update_category](#lunchable.LunchMoney.update_category) | Update a single category | +| PUT | [update_crypto](#lunchable.LunchMoney.update_crypto) | Update a Manual Crypto Asset | +| PUT | [update_transaction](#lunchable.LunchMoney.update_transaction) | Update a Transaction | +| DELETE | [remove_budget](#lunchable.LunchMoney.remove_budget) | Unset an Existing Budget for a Particular Category in a Particular Month | +| DELETE | [remove_category](#lunchable.LunchMoney.remove_category) | Delete a single category | +| DELETE | [remove_category_force](#lunchable.LunchMoney.remove_category_force) | Forcefully delete a single category | +| DELETE | [remove_transaction_group](#lunchable.LunchMoney.remove_transaction_group) | Delete a Transaction Group | + +## Low Level Methods + +| Name | Description | +|------------------------------------------------------------|------------------------------------------------| +| [amake_request](#lunchable.LunchMoney.amake_request) | Make an async HTTP Request and return its data | +| [arequest](#lunchable.LunchMoney.arequest) | Make an async HTTP Request | +| [make_request](#lunchable.LunchMoney.make_request) | Make an HTTP Request and return its data | +| [process_response](#lunchable.LunchMoney.process_response) | Process a Lunch Money Response | +| [request](#lunchable.LunchMoney.request) | Make an HTTP Request | + +## Attributes + +| Name | Description | +|------------------------------------------------------|----------------------------------| +| [async_session](#lunchable.LunchMoney.async_session) | Authenticated Async HTTPX Client | +| [session](#lunchable.LunchMoney.session) | Authenticated HTTPX Client | + +## Class Documentation + +::: lunchable.LunchMoney + handler: python + options: + show_bases: false + allow_inspection: true + inherited_members: true + group_by_category: true + heading_level: 3 + show_source: false diff --git a/docs/plugins/index.md b/docs/plugins/index.md new file mode 100644 index 00000000..ae715937 --- /dev/null +++ b/docs/plugins/index.md @@ -0,0 +1,10 @@ +# Plugins + +lunchable supports plugins with other, external, services. See below for what's been built already. +If you can't find what you're looking for, consider building it yourself and opening a pull-request. + +### [PushLunch](pushlunch.md): Push Notifications via Pushover + +### [SplitLunch](splitlunch.md): Splitwise Integration + +### [PrimeLunch](primelunch.md): Amazon Transaction Updater diff --git a/docs/source/primelunch.md b/docs/plugins/primelunch.md similarity index 71% rename from docs/source/primelunch.md rename to docs/plugins/primelunch.md index e690b89e..0e335294 100644 --- a/docs/source/primelunch.md +++ b/docs/plugins/primelunch.md @@ -32,7 +32,7 @@ the [Amazon Order History Reporter](https://chrome.google.com/webstore/detail/am plugin because it gives us some functionality that Amazon doesn't: exporting Amazon transactions as they're grouped on actual credit card transactions. -## Run via the [Lunchable CLI](cli.md#lunchable-cli) +## Run via the [Lunchable CLI](../cli.md#lunchable-cli) You can install lunchable with [pip](https://pypi.org/project/lunchable/) or [pipx](https://pypa.github.io/pipx/): @@ -51,18 +51,20 @@ The below command runs the `PrimeLunch` update tool: lunchable plugins primelunch run -f ~/Downloads/amazon_order_history.csv ``` -:::{important} -The commands on this documentation correspond to running `PrimeLunch` on a -Mac or Linux Machine. If you are a Windows user take note of the following items: - -- Multiline commands in Windows machines use the `^` character instead of `\` to escape new lines -- On macs, the default CSV file is located at `~/Downloads/amazon_order_history.csv`, on Windows this file - is located someplace like `C:\Users\YourUserName\Downloads\amazon_order_history.csv` -- It's recommended you use the new - [Windows Terminal](https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701) - to run `PrimeLunch` - -::: +> IMPORTANT: **Windows Users** +> +> The commands on this documentation correspond to running on a +> Mac or Linux Machine. If you are a Windows user take note of the following items: +> +> - Multiline commands in Windows machines use the `^` character instead of `\` to escape new lines +> - On macs, the default CSV file is located at `~/Downloads/amazon_order_history.csv`, on Windows this file +> is located someplace like `C:\Users\YourUserName\Downloads\amazon_order_history.csv` +> - My personal recommendation is to use the +> [Windows Terminal](https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701) +> along with +> [WSL](https://learn.microsoft.com/en-us/windows/wsl/) (Windows Subsystem for Linux) to +> access a Linux shell on your Windows machine. This will allow you to use the commands +> as written. The below command runs the `PrimeLunch` update tool using a date window of fourteen days instead of the default seven days (these larger windows are especially useful for finding refunds and recurring @@ -93,11 +95,13 @@ lunchable plugins primelunch run \ ## Command Line Documentation -```{eval-rst} -.. click:: lunchable._cli:primelunch - :prog: lunchable plugins primelunch - :nested: full -``` +::: mkdocs-click + :module: lunchable.plugins.primelunch.primelunch + :command: run_primelunch + :prog_name: lunchable plugins primelunch run + :style: table + :list_subcommands: True + ## References diff --git a/docs/plugins/pushlunch.md b/docs/plugins/pushlunch.md new file mode 100644 index 00000000..8591b8ec --- /dev/null +++ b/docs/plugins/pushlunch.md @@ -0,0 +1,51 @@ +# PushLunch: Push Notifications via Pushover + +
+

+ lunchable + lunchable +

+
+ +--- + +`PushLunch` supports Push Notifications via [Pushover](https://pushover.net). Pushover supports iOS +and Android Push notifications. To get started just provide your Pushover +`User Key` directly or via the `PUSHOVER_USER_KEY` environment variable. + +## Run via the Lunchable CLI + +The below command checks for un-reviewed transactions in the current period +and sends them as Push Notifications. The `--continuous` flag tells it to run +forever which will only send you a push notification once for each transaction. +By default it will check every 60 minutes, but this can be changed using the +`--interval` argument. + +```console +lunchable plugins pushlunch notify --continuous +``` + +## Run via Docker + +```console +docker run --rm \ + --env LUNCHMONEY_ACCESS_TOKEN=${LUNCHMONEY_ACCESS_TOKEN} \ + --env PUSHOVER_USER_KEY=${PUSHOVER_USER_KEY} \ + juftin/lunchable:latest \ + lunchable plugins pushlunch notify --continuous +``` + +## Run via Python + +```python +from lunchable.plugins.pushlunch import PushLunch +``` + +::: lunchable.plugins.pushlunch.PushLunch + handler: python + options: + show_bases: false + allow_inspection: true + heading_level: 3 diff --git a/docs/plugins/splitlunch.md b/docs/plugins/splitlunch.md new file mode 100644 index 00000000..e184ec1a --- /dev/null +++ b/docs/plugins/splitlunch.md @@ -0,0 +1,114 @@ +# SplitLunch: Splitwise Integration + +
+

+ lunchable + lunchable +

+
+ +--- + +## Integrations + +This plugin supports different operations, and some of those operations have prerequisites: + +### Auto Importer + +It supports the auto-importing of Splitwise expenses into Lunch Money transactions. This requires +a manual asset exist in your Lunch Money account with "Splitwise" in the Name. Expenses that +have been deleted or which don't impact you (i.e. are only between other users in your group) +are skipped. By default, payments and expenses for which you are recorded as the payer are +skipped as well, but these can be overridden by the `--allow-payments` and `--allow-self-paid` +CLI flags, respectively. + +#### Prerequisites + +- Accounts: + - Splitwise must be in the account name + +### LunchMoney -> Splitwise + +It supports the creation of Splitwise transactions directly from synced Lunch Money accounts. This syncing requires you create a tag called `SplitLunchImport`. Transactions with this tag will be created in Splitwise with your "financial partner". Once transactions are created in Splitwise they will be split in half in Lunch Money. Half of the split will be marked in the `Reimbursement` category which must be created. + +#### Prerequisites + +- Financial Partners: + - If you only have one friend in Splitwise, this is your Financial Partner + - Financial Partners can be individual users or groups and transactions will be split accordingly + - Financial Partners must be specified by their Splitwise Group ID, Splitwise User ID, or Email Address +- Tags: + - `SplitLunchImport` +- Categories: + - `Reimbursement` + +### SplitLunch + +It supports a workflow where you mark transactions as split (identical to `Lunch Money -> Splitwise`) without importing them into Splitwise. This syncing requires you create a tag called `SplitLunch` and a category named `Reimbursement` + +#### Prerequisites + +- Tags: + - `SplitLunch` +- Categories: + - `Reimbursement` + +### LunchMoney -> Splitwise (without splitting) + +It supports the creation of Splitwise transactions directly from synced Lunch Money accounts. This syncing requires you create a tag called `SplitLunchDirectImport`. Transactions with this tag will be created in Splitwise with the total completely owed by your "financial partner". The entire transaction wil then be categorized as `Reimbursement` without being split. + +#### Prerequisites + +- Financial Partners: + - If you only have one friend in Splitwise, this is your Financial Partner + - Financial Partners can be individual users or groups and transactions will be split accordingly + - Financial Partners must be specified by their Splitwise Group ID, Splitwise User ID, or Email Address +- Tags: + - `SplitLunchDirectImport` +- Categories: + - `Reimbursement` + +> **Note:** Some of the above scenarios allow for tagging of a `Splitwise` tag on updated transactions. This tag must be created for this functionality to work. + +## Installation + +```shell +pip install lunchable[splitlunch] +``` + +## Run the SplitLunch plugin for the Lunchable CLI + +```shell +lunchable plugins splitlunch --help +``` + +## Run the SplitLunch plugin for the Lunchable CLI via Docker + +```shell +docker pull juftin/lunchable +``` + +```shell +docker run \ + --env LUNCHMONEY_ACCESS_TOKEN=${LUNCHMONEY_ACCESS_TOKEN} \ + --env SPLITWISE_CONSUMER_KEY=${SPLITWISE_CONSUMER_KEY} \ + --env SPLITWISE_CONSUMER_SECRET=${SPLITWISE_CONSUMER_SECRET} \ + --env SPLITWISE_API_KEY=${SPLITWISE_API_KEY} \ + juftin/lunchable:latest \ + lunchable plugins splitlunch --help +``` + +## Run via Python + +```python +from lunchable.plugins.splitlunch import SplitLunch +``` + +::: lunchable.plugins.splitlunch.SplitLunch + handler: python + options: + show_bases: false + allow_inspection: true + heading_level: 3 diff --git a/docs/requirements.txt b/docs/requirements.txt deleted file mode 100644 index ca6a57a6..00000000 --- a/docs/requirements.txt +++ /dev/null @@ -1,17 +0,0 @@ -sphinx -sphinx-rtd-theme -autodocsumm -myst-parser[linkify] -autoclasstoc -sphinx-copybutton -sphinx_autodoc_defaultargs -sphinxcontrib-apidoc -sphinx-click -sphinx-autodoc-typehints -autodoc_pydantic - -requests -pydantic -splitwise -python-dateutil -click diff --git a/docs/source/cli.md b/docs/source/cli.md deleted file mode 100644 index d83c7233..00000000 --- a/docs/source/cli.md +++ /dev/null @@ -1,7 +0,0 @@ -# lunchable CLI - -```{eval-rst} -.. click:: lunchable._cli:cli - :prog: lunchable - :nested: full -``` diff --git a/docs/source/cli.rst b/docs/source/cli.rst deleted file mode 100644 index 1141e676..00000000 --- a/docs/source/cli.rst +++ /dev/null @@ -1,182 +0,0 @@ -################## -Lunchable CLI -################## - -.. code-block:: console - - Usage: lunchable [OPTIONS] COMMAND [ARGS]... - - Interactions with Lunch Money via lunchable 🍱 - - Options: - --version Show the version and exit. - --access-token TEXT LunchMoney Developer API Access Token - --debug / --no-debug Enable extra debugging output - --help Show this message and exit. - - Commands: - http Interact with the LunchMoney API - plugins Interact with Lunchable Plugins - transactions Interact with Lunch Money transactions - -****************** -Installation -****************** - -To use lunchable on the command line, first install it using `pip `_ or -`pipx `_: - -.. code-block:: console - - pip install lunchable - - -or, if you're using the Splitwise plugin on the CLI: - -.. code-block:: console - - pip install "lunchable[splitwise]" - -Install Shell Completion -========================= - - -bash -################### - -.. code-block:: console - - _LUNCHABLE_COMPLETE=bash_source lunchable > ~/.lunchable-complete.bash - echo "[[ ! -f ~/.lunchable-complete.bash ]] || source ~/.lunchable-complete.bash" >> ~/.bashrc - -zsh -################### - -.. code-block:: console - - _LUNCHABLE_COMPLETE=zsh_source lunchable > ~/.lunchable-complete.zsh - echo "[[ ! -f ~/.lunchable-complete.zsh ]] || source ~/.lunchable-complete.zsh" >> ~/.zshrc - -Run via Docker -============== - -.. code-block:: console - - docker pull juftin/lunchable - -.. code-block:: console - - docker run \ - --env LUNCHMONEY_ACCESS_TOKEN=${LUNCHMONEY_ACCESS_TOKEN} \ - juftin/lunchable:latest \ - lunchable transactions get --limit 5 - -****************** -Examples -****************** - -.. code-block:: console - - pip install --upgrade lunchable - export LUNCHMONEY_ACCESS_TOKEN="xxxxxxxxxxx" - -.. code-block:: console - - lunchable http /v1/me - -.. code-block:: json - - { - "user_name": "Justin Flannery", - "user_email": "Justin@example.com", - "user_id": 99999, - "account_id": 99999, - "budget_name": "🤖 Justin", - "api_key_label": "Testing" - } - -.. code-block:: console - - lunchable http -X GET https://dev.lunchmoney.app/v1/assets - -.. code-block:: json - - { - "assets": [ - { - "id": 99999, - "type_name": "cash", - "subtype_name": "digital wallet (paypal, venmo)", - "name": "Test Account", - "display_name": "Test Account", - "balance": "190.2100", - "balance_as_of": "2022-04-23T07:23:20.000Z", - "closed_on": "2022-04-23", - "currency": "usd", - "institution_name": "Test", - "exclude_transactions": true, - "created_at": "2021-09-20T05:32:29.060Z" - } - ] - } - -.. code-block:: console - - lunchable http -X PUT /v1/assets/99999 --data '{"balance": 200.00}' - -.. code-block:: json - - { - "id": 99999, - "type_name": "cash", - "subtype_name": "digital wallet (paypal, venmo)", - "name": "Test Account", - "display_name": "Test Account", - "balance": "200.0000", - "balance_as_of": "2022-10-21T04:22:50.391Z", - "closed_on": "2022-04-23", - "currency": "usd", - "institution_name": "Test", - "exclude_transactions": true, - "created_at": "2021-09-20T05:32:29.060Z" - } - -.. code-block:: console - - lunchable transactions get --limit 1 --start-date 2022-09-07 --end-date 2022-09-15 | jq - -.. code-block:: json - - [ - { - "id": 120998527, - "date": "2022-09-07", - "payee": "Ally Bank", - "amount": -87.5, - "currency": "usd", - "notes": "ATCO Transfer", - "category_id": 229148, - "asset_id": null, - "plaid_account_id": 41573, - "status": "cleared", - "parent_id": null, - "is_group": false, - "group_id": null, - "tags": null, - "external_id": null, - "original_name": "Internet transfer from Interest Checking account XXXXXX2045", - "type": null, - "subtype": null, - "fees": null, - "price": null, - "quantity": null - } - ] - -****************** -Documentation -****************** - -.. click:: lunchable._cli:cli - :prog: lunchable - :nested: full diff --git a/docs/source/conf.py b/docs/source/conf.py deleted file mode 100644 index 16f0434b..00000000 --- a/docs/source/conf.py +++ /dev/null @@ -1,102 +0,0 @@ -""" -Sphinx Documentation Generator -""" - -import sys -from datetime import datetime -from pathlib import Path - -_project_path = Path(__file__).resolve().parent.parent.parent -_project_dir = str(_project_path) -sys.path.insert(0, _project_dir) - -from lunchable._version import __application__, __author__, __version__ # noqa - -_author = __author__ -project = __application__ -copyright = f"{datetime.now().year}, {_author}" -author = _author -release = version = __version__ - -extensions = [ - "sphinx.ext.napoleon", - "sphinx.ext.autodoc", - "sphinx.ext.autosummary", - "sphinx.ext.coverage", - "sphinx.ext.viewcode", - "sphinx.ext.intersphinx", - "sphinx.ext.autosectionlabel", - "sphinxcontrib.apidoc", - "sphinxcontrib.autodoc_pydantic", - "autodocsumm", - "myst_parser", - "autoclasstoc", - "sphinx_copybutton", - "sphinx_autodoc_typehints", - "sphinx_autodoc_defaultargs", - "sphinx_click", -] - -myst_heading_anchors = 5 -myst_enable_extensions = [ - "amsmath", - "colon_fence", - "deflist", - "dollarmath", - "fieldlist", - "html_admonition", - "html_image", - "linkify", - "replacements", - "smartquotes", - "strikethrough", - "substitution", - "tasklist", -] - -templates_path = ["_templates"] -html_static_path = ["_static"] -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] - -html_theme = "sphinx_rtd_theme" -html_theme_options = { - "display_version": True, -} -html_show_sphinx = False -html_show_sourcelink = False -# html_logo = "_static/lunchable.png" -html_favicon = "https://juftin.com/favicon.ico" - -source_suffix = { - ".rst": "restructuredtext", - ".txt": "markdown", - ".md": "markdown", -} - -autosummary_generate = True -intersphinx_mapping = { - "python": ("https://docs.python.org/3", None), -} - -source_code_dir = _project_path.joinpath("lunchable") -apidoc_module_dir = str(source_code_dir) -apidoc_output_dir = str(source_code_dir.parent.joinpath("docs", "source", "api")) -apidoc_excluded_paths = ["tests"] -apidoc_separate_modules = True - -autodoc_member_order = "bysource" -autodoc_pydantic_model_show_json = False -autodoc_pydantic_settings_show_json = False - -always_document_default_args = True -docstring_default_arg_substitution = "**[Default]:**" - -autodoc_default_options = {"exclude-members": "with_traceback"} - -html_favicon = "https://juftin.com/favicon.ico" -html_context = { - "display_github": True, - "github_user": "juftin", - "github_repo": "lunchable", - "github_version": "main/docs/source/", -} diff --git a/docs/source/index.rst b/docs/source/index.rst deleted file mode 100644 index 39073f95..00000000 --- a/docs/source/index.rst +++ /dev/null @@ -1,83 +0,0 @@ -**lunchable** -=================================== - -.. image:: https://i.imgur.com/FyKDsG3.png - :width: 400 - :align: center - :alt: lunchable - :target: https://github.com/juftin/lunchable - -**lunchable** is a Python Client for the -`Lunch Money Developer API `_. -It's built on top of `pydantic `_ -and `httpx `_, -it offers an *intuitive* API, a *simple* CLI, -complete coverage of all endpoints, -and *plugins* to other external services - -.. image:: https://img.shields.io/pypi/v/lunchable?color=blue&label=lunchable - :target: https://github.com/juftin/lunchable - :alt: Lunchable Version -.. image:: https://img.shields.io/pypi/pyversions/lunchable - :target: https://pypi.python.org/pypi/lunchable/ - :alt: PyPI -.. image:: https://img.shields.io/docker/v/juftin/lunchable?color=blue&label=docker&logo=docker - :target: https://hub.docker.com/r/juftin/lunchable - :alt: Docker -.. image:: https://github.com/juftin/lunchable/actions/workflows/tests.yaml/badge.svg?branch=main - :target: https://github.com/juftin/lunchable/actions/workflows/tests.yaml?query=branch%3Amain - :alt: Testing Status -.. image:: https://img.shields.io/github/license/juftin/lunchable?color=blue&label=License - :target: https://github.com/juftin/lunchable/blob/main/LICENSE - :alt: GitHub License - -.. code-block:: console - - pip install lunchable - -.. code-block:: python - - from typing import Any, Dict, List - - from lunchable import LunchMoney - from lunchable.models import TransactionObject - - lunch = LunchMoney(access_token="xxxxxxxxxxx") - transactions: List[TransactionObject] = lunch.get_transactions() - - first_transaction: TransactionObject = transactions[0] - transaction_as_dict: Dict[str, Any] = first_transaction.model_dump() - -.. code-block:: console - - export LUNCHMONEY_ACCESS_TOKEN="xxxxxxxxxxx" - lunchable transactions get --limit 5 - -.. toctree:: - :maxdepth: 1 - :caption: Contents: - - usage.rst - lunchable.rst - plugins.rst - Command Line Interface ⌨️ - API Documentation 🤖 - Contributing 👥 - GitHub 🛠 - Changelog 📝 - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - - - -.. image:: https://raw.githubusercontent.com/juftin/juftin/main/static/juftin.png - :width: 60 - :height: 60 - :align: center - :alt: juftin - :target: https://github.com/juftin diff --git a/docs/source/lunchable.rst b/docs/source/lunchable.rst deleted file mode 100644 index 9e25538c..00000000 --- a/docs/source/lunchable.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. _interacting-with-lunchable: - -Interacting with Lunch Money -=================================== - -.. code-block:: python - - from lunchable import LunchMoney - - lunch = LunchMoney(access_token="xxxxxxx") - -.. currentmodule:: lunchable - -.. autoclass:: LunchMoney - :members: - :inherited-members: - :autosummary: - :toctree: diff --git a/docs/source/plugins.rst b/docs/source/plugins.rst deleted file mode 100644 index 1da70045..00000000 --- a/docs/source/plugins.rst +++ /dev/null @@ -1,14 +0,0 @@ -==================== -Plugins -==================== - -lunchable supports plugins with other, external, services. -See below for what's been built already. If you can't find what you're -looking for, consider building it yourself and opening a pull-request. - -.. toctree:: - :maxdepth: 1 - - pushlunch.rst - splitlunch.rst - primelunch.rst diff --git a/docs/source/pushlunch.rst b/docs/source/pushlunch.rst deleted file mode 100644 index 5f9bfdc2..00000000 --- a/docs/source/pushlunch.rst +++ /dev/null @@ -1,56 +0,0 @@ -########################################### -PushLunch: Push Notifications via Pushover -########################################### - -|pic1| |pic2| - -.. |pic1| image:: https://pushover.net/images/pushover-logo.svg - :width: 35% - :alt: pushover - :target: https://www.splitwise.com/ - -.. |pic2| image:: https://i.imgur.com/FyKDsG3.png - :width: 60% - :alt: lunchable - :target: https://github.com/juftin/lunchable - --------- - -`PushLunch` supports Push Notifications via `Pushover `_. Pushover -supports iOS and Android Push notifications. To get started just provide your Pushover -`User Key` directly or via the `PUSHOVER_USER_KEY` environment variable. - - -Run via the :ref:`Lunchable CLI` -================================ - -The below command checks for un-reviewed transactions in the current period and -sends them as Push Notifications. The `--continuous` flag tells it to run forever which -will only send you a push notifaction once for each transaction. -By default it will check every 60 minutes, but this can be changed using the `--interval` -argument. - -.. code-block:: console - - lunchable plugins pushlunch notify --continuous - -Run via Docker -=============== - -.. code-block:: console - - docker run --rm \ - --env LUNCHMONEY_ACCESS_TOKEN=${LUNCHMONEY_ACCESS_TOKEN} \ - --env PUSHOVER_USER_KEY=${PUSHOVER_USER_KEY} \ - juftin/lunchable:latest \ - lunchable plugins pushlunch notify --continuous - -Run via Python -=============== - -.. currentmodule:: lunchable.plugins.pushlunch - -.. autoclass:: PushLunch - :members: - :autosummary: - :toctree: _autosummary diff --git a/docs/source/splitlunch.rst b/docs/source/splitlunch.rst deleted file mode 100644 index d490b6a7..00000000 --- a/docs/source/splitlunch.rst +++ /dev/null @@ -1,138 +0,0 @@ -################################# -SplitLunch: Splitwise Integration -################################# - -|pic1| |pic2| - -.. |pic1| image:: https://assets.splitwise.com/assets/core/logo-square.svg - :width: 35% - :alt: splitwise - :target: https://www.splitwise.com/ - -.. |pic2| image:: https://i.imgur.com/FyKDsG3.png - :width: 60% - :alt: lunchable - :target: https://github.com/juftin/lunchable - --------- - -Integrations -============ - -This plugin supports different operations, and some of those operations -have prerequisites: - -Auto Importer -------------- -It supports the auto-importing of Splitwise expenses into Lunch Money transactions. This requires a -manual asset exist in your Lunch Money account with "Splitwise" in the Name. Expenses that have been -deleted or which don't impact you (i.e. are only between other users in your group) are skipped. By -default, payments and expenses for which you are recorded as the payer are skipped as well, but -these can be overridden by the `--allow-payments` and `--allow-self-paid` CLI flags, respectively. - - Prerequisites: - - Accounts: - - Splitwise must be in the account name - - - -LunchMoney -> Splitwise ------------------------ -It supports the creation of Splitwise transactions directly from synced Lunch Money -accounts. This syncing requires you create a tag called `SplitLunchImport`. Transactions -with this tag will be created in Splitwise with your "financial partner". Once transactions -are created in Splitwise they will be split in half in Lunch Money. Half of the split will be -marked in the `Reimbursement` category which must be created. - - Prerequisites: - - Financial Partners: - - If you only have one friend in Splitwise, this is your Financial Partner - - Financial Partners can be individual users or groups and transactions will be split accordingly - - Financial Partners must be specified by their Splitwise Group ID, Splitwise User ID, or Email Address - - Tags: - - `SplitLunchImport` - - Categories: - - `Reimbursement` - -SplitLunch ----------- -It supports a workflow where you mark transactions as split -(identical to `Lunch Money -> Splitwise`) without importing them into Splitwise. -This syncing requires you create a tag called `SplitLunch` and a category named -`Reimbursement` - - Prerequisites: - - Tags: - - `SplitLunch` - - Categories: - - `Reimbursement` - -LunchMoney -> Splitwise (without splitting) -------------------------------------------- -It supports the creation of Splitwise transactions directly from synced Lunch Money -accounts. This syncing requires you create a tag called `SplitLunchDirectImport`. Transactions -with this tag will be created in Splitwise with the total completely owed by your -"financial partner". The entire transaction wil then be categorized as `Reimbursement` without -being split. - - Prerequisites: - - Financial Partners: - - If you only have one friend in Splitwise, this is your Financial Partner - - Financial Partners can be individual users or groups and transactions will be split accordingly - - Financial Partners must be specified by their Splitwise Group ID, Splitwise User ID, or Email Address - - Tags: - - `SplitLunchDirectImport` - - Categories: - - `Reimbursement` - -.. note:: - - Some of the above scenarios allow for tagging of a `Splitwise` - tag on updated transactions. This tag must be created for this - functionality to work. - -Installation -============ - -.. code-block:: console - - pip install lunchable[splitlunch] - -Run the SplitLunch plugin for the :ref:`Lunchable CLI` -====================================================== - -.. code-block:: console - - lunchable plugins splitlunch --help - - -Run the SplitLunch plugin for the :ref:`Lunchable CLI` via Docker -================================================================== - -.. code-block:: console - - docker pull juftin/lunchable - -.. code-block:: console - - docker run \ - --env LUNCHMONEY_ACCESS_TOKEN=${LUNCHMONEY_ACCESS_TOKEN} \ - --env SPLITWISE_CONSUMER_KEY=${SPLITWISE_CONSUMER_KEY} \ - --env SPLITWISE_CONSUMER_SECRET=${SPLITWISE_CONSUMER_SECRET} \ - --env SPLITWISE_API_KEY=${SPLITWISE_API_KEY} \ - juftin/lunchable:latest \ - lunchable plugins splitlunch --help - -Run via Python -=============== - -.. code-block:: python - - from lunchable.plugins.splitlunch import SplitLunch - -.. currentmodule:: lunchable.plugins.splitlunch - -.. autoclass:: SplitLunch - :members: - :autosummary: - :toctree: _autosummary diff --git a/docs/source/usage.rst b/docs/source/usage.rst deleted file mode 100644 index dd8c30c1..00000000 --- a/docs/source/usage.rst +++ /dev/null @@ -1,115 +0,0 @@ -################## -Usage -################## - -****************** -Installation -****************** - -To use lunchable, first install it using pip: - -.. code-block:: console - - pip install lunchable - -****************** -Examples -****************** - -Read more about :ref:`interacting-with-lunchable` to see what -else you can do. - -Transactions -================== - -Retrieve a list of :class:`.TransactionObject` ----------------------------------------------------------------------- - -.. code-block:: python - - from lunchable import LunchMoney - - lunch = LunchMoney(access_token="xxxxxxx") - transactions = lunch.get_transactions(start_date="2020-01-01", - end_date="2020-01-31") - - -Retrieve a single transaction (:class:`.TransactionObject`) ----------------------------------------------------------------------- - -.. code-block:: python - - from lunchable import LunchMoney - - lunch = LunchMoney(access_token="xxxxxxx") - transaction = lunch.get_transaction(transaction_id=1234) - - -The above code returns a :class:`.TransactionObject` with ID # 1234 (assuming it exists) - -Update a transaction with a :class:`.TransactionUpdateObject` ----------------------------------------------------------------------- - -.. code-block:: python - - from datetime import datetime - - from lunchable import LunchMoney, TransactionUpdateObject - - lunch = LunchMoney(access_token="xxxxxxx") - transaction_note = f"Updated on {datetime.now()}" - notes_update = TransactionUpdateObject(notes=transaction_note) - response = lunch.update_transaction(transaction_id=1234, - transaction=notes_update) - -Update a :class:`.TransactionObject` with itself ----------------------------------------------------------------------- - -.. code-block:: python - - from datetime import datetime, timedelta - - from lunchable import LunchMoney - - lunch = LunchMoney(access_token="xxxxxxx") - transaction = lunch.get_transaction(transaction_id=1234) - - transaction.notes = f"Updated on {datetime.now()}" - transaction.date = transaction.date + timedelta(days=1) - response = lunch.update_transaction(transaction_id=transaction.id, - transaction=transaction) - -Create a new transaction with a :class:`.TransactionInsertObject` ----------------------------------------------------------------------- - -.. code-block:: python - - from lunchable import LunchMoney, TransactionInsertObject - - lunch = LunchMoney(access_token="xxxxxxx") - - new_transaction = TransactionInsertObject(payee="Example Restaurant", - amount=120.00, - notes="Saturday Dinner") - new_transaction_ids = lunch.insert_transactions(transactions=new_transaction) - -Use the :ref:`Lunchable CLI` ----------------------------- - -.. code-block:: console - - lunchable transactions get --limit 5 - -Use the :ref:`Lunchable CLI` via Docker ---------------------------------------- - -.. code-block:: console - - docker pull juftin/lunchable - -.. code-block:: console - - docker run \ - --env LUNCHMONEY_ACCESS_TOKEN=${LUNCHMONEY_ACCESS_TOKEN} \ - juftin/lunchable:latest \ - lunchable transactions get --limit 5 diff --git a/docs/source/_static/lunchable.png b/docs/static/lunchable.png similarity index 100% rename from docs/source/_static/lunchable.png rename to docs/static/lunchable.png diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 00000000..c814bcb9 --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,130 @@ +# Usage + +## Installation + +To use lunchable, first install it using pip: + +```shell +pip install lunchable +``` + +## Client + +The [LunchMoney](interacting.md#interacting-with-lunch-money) client is the main entrypoint +for interacting with the Lunch Money API. It defaults to inheriting the `LUNCHMONEY_ACCESS_TOKEN` +environment variable, but can be created with an explicit `access_token` parameter. + +```python +from lunchable import LunchMoney + +lunch = LunchMoney(access_token="xxxxxxx") +``` + +Read more about [Interacting with Lunch Money](interacting.md#lunchmoney) +to see what else you can do. + +# Transactions + +## Retrieve a list of [`TransactionObject`][lunchable.models.transactions.TransactionObject] + +```python +from __future__ import annotations + +from lunchable import LunchMoney +from lunchable.models import TransactionObject + +lunch = LunchMoney(access_token="xxxxxxx") +transactions: list[TransactionObject] = lunch.get_transactions( + start_date="2020-01-01", + end_date="2020-01-31" +) +``` + +## Retrieve a single transaction ([`TransactionObject`][lunchable.models.transactions.TransactionObject]) + +```python +from lunchable import LunchMoney +from lunchable.models import TransactionObject + +lunch = LunchMoney(access_token="xxxxxxx") +transaction: TransactionObject = lunch.get_transaction(transaction_id=1234) +``` + +The above code returns a TransactionObject with ID # 1234 (assuming it exists) + +## Update a transaction with a [`TransactionUpdateObject`][lunchable.models.transactions.TransactionUpdateObject] + +```python +from __future__ import annotations + +from datetime import datetime +from typing import Any + +from lunchable import LunchMoney +from lunchable.models import TransactionUpdateObject + +lunch = LunchMoney(access_token="xxxxxxx") +transaction_note = f"Updated on {datetime.now()}" +notes_update = TransactionUpdateObject(notes=transaction_note) +response: dict[str, Any] = lunch.update_transaction( + transaction_id=1234, + transaction=notes_update +) +``` + +## Update a TransactionObject with itself + +```python +from datetime import datetime, timedelta + +from lunchable import LunchMoney +from lunchable.models import TransactionObject + +lunch = LunchMoney(access_token="xxxxxxx") +transaction: TransactionObject = lunch.get_transaction(transaction_id=1234) + +transaction.notes = f"Updated on {datetime.now()}" +transaction.date = transaction.date + timedelta(days=1) +response = lunch.update_transaction( + transaction_id=transaction.id, + transaction=transaction +) +``` + +## Create a new transaction with a [`TransactionInsertObject`][lunchable.models.transactions.TransactionInsertObject] + +`transactions` can be a single [`TransactionInsertObject`][lunchable.models.transactions.TransactionInsertObject] +or a list of [`TransactionInsertObject`][lunchable.models.transactions.TransactionInsertObject]. + +```python +from lunchable import LunchMoney +from lunchable.models import TransactionInsertObject + +lunch = LunchMoney(access_token="xxxxxxx") + +new_transaction = TransactionInsertObject( + payee="Example Restaurant", + amount=120.00, + notes="Saturday Dinner" +) +new_transaction_ids = lunch.insert_transactions(transactions=new_transaction) +``` + +## Use the Lunchable CLI + +```shell +lunchable transactions get --limit 5 +``` + +## Use the Lunchable CLI via Docker + +```shell +docker pull juftin/lunchable +``` + +```shell +docker run \ + --env LUNCHMONEY_ACCESS_TOKEN=${LUNCHMONEY_ACCESS_TOKEN} \ + juftin/lunchable:latest \ + lunchable transactions get --limit 5 +``` diff --git a/lunchable/models/_base.py b/lunchable/models/_base.py index bee6c903..daa8efd1 100644 --- a/lunchable/models/_base.py +++ b/lunchable/models/_base.py @@ -2,7 +2,19 @@ Base Pydantic Object for Containers """ -from pydantic import BaseModel +import textwrap +from typing import Any + +from pydantic import BaseModel, Field + + +def LunchableField(*args: Any, **kwargs: Any) -> Any: + """ + Custom Field for Lunchable Models + """ + if "description" in kwargs: + kwargs["description"] = textwrap.dedent(kwargs["description"]).strip() + return Field(*args, **kwargs) class LunchableModel(BaseModel): diff --git a/lunchable/models/_core.py b/lunchable/models/_core.py index 236b2ff6..aa6836d0 100644 --- a/lunchable/models/_core.py +++ b/lunchable/models/_core.py @@ -158,28 +158,32 @@ def request( Examples -------- A recent use of this method was to delete a Tag (which isn't available via the - Developer API yet) :: - - import lunchable - - lunch = lunchable.LunchMoney() - - # Get All the Tags - all_tags = lunch.get_tags() - # Get All The Null Tags (a list of 1 or zero) - null_tags = [tag for tag in all_tags if tag.name in [None, ""]] - - # Create a Cookie dictionary from a browser session - cookies = {"cookie_keys": "cookie_values"} - - for null_tag in null_tags: - # use the httpx.client embedded in the class to make a request with cookies - response = lunch.request( - method="DELETE", - url=f"https://api.lunchmoney.app/tags/{null_tag.id}", - cookies=cookies) - # raise an error for 4XX responses - response.raise_for_status() + Developer API yet) + + ```python + import lunchable + + lunch = lunchable.LunchMoney() + + # Get All the Tags + all_tags = lunch.get_tags() + # Get All The Null Tags (a list of 1 or zero) + null_tags = [tag for tag in all_tags if tag.name in [None, ""]] + + # Create a Cookie dictionary from a browser session + cookies = {"cookie_keys": "cookie_values"} + del lunch.session.headers["authorization"] + + for null_tag in null_tags: + # use the httpx.client embedded in the class to make a request with cookies + response = lunch.request( + method=lunch.Methods.DELETE, + url=f"https://api.lunchmoney.app/tags/{null_tag.id}", + cookies=cookies + ) + # raise an error for 4XX responses + response.raise_for_status() + ``` """ response = self.session.request( method=method, diff --git a/lunchable/models/_lunchmoney.py b/lunchable/models/_lunchmoney.py index 9127749d..f0fcbfb8 100644 --- a/lunchable/models/_lunchmoney.py +++ b/lunchable/models/_lunchmoney.py @@ -38,18 +38,21 @@ class LunchMoney( Lunch Money Python Client. This class facilitates with connections to - the `Lunch Money Developer API `_. Authenticate + the [Lunch Money Developer API](https://lunchmoney.dev/). Authenticate with an Access Token. If an access token isn't provided one will attempt to be inherited from a `LUNCHMONEY_ACCESS_TOKEN` environment variable. Examples -------- - :: + ```python + from __future__ import annotations - from lunchable import LunchMoney + from lunchable import LunchMoney + from lunchable.models import TransactionObject - lunch = LunchMoney(access_token="xxxxxxx") - transactions = lunch.get_transactions() + lunch = LunchMoney(access_token="xxxxxxx") + transactions: list[TransactionObject] = lunch.get_transactions() + ``` """ def __init__(self, access_token: Optional[str] = None): diff --git a/lunchable/models/assets.py b/lunchable/models/assets.py index 2465d371..8491bd0b 100644 --- a/lunchable/models/assets.py +++ b/lunchable/models/assets.py @@ -8,9 +8,10 @@ import logging from typing import List, Optional, Union -from pydantic import Field, field_validator +from pydantic import field_validator from lunchable._config import APIConfig +from lunchable.models._base import LunchableField as Field from lunchable.models._base import LunchableModel from lunchable.models._core import LunchMoneyAPIClient diff --git a/lunchable/models/budgets.py b/lunchable/models/budgets.py index da78bb9b..4c1db307 100644 --- a/lunchable/models/budgets.py +++ b/lunchable/models/budgets.py @@ -8,9 +8,8 @@ import logging from typing import Any, Dict, List, Optional -from pydantic import Field - from lunchable._config import APIConfig +from lunchable.models._base import LunchableField as Field from lunchable.models._base import LunchableModel from lunchable.models._core import LunchMoneyAPIClient @@ -140,7 +139,9 @@ def get_budgets( """ params = BudgetParamsGet(start_date=start_date, end_date=end_date).model_dump() response_data = self.make_request( - method="GET", url_path=[APIConfig.LUNCHMONEY_BUDGET], params=params + method=self.Methods.GET, + url_path=[APIConfig.LUNCHMONEY_BUDGET], + params=params, ) budget_objects = [BudgetObject.model_validate(item) for item in response_data] return budget_objects @@ -191,7 +192,9 @@ def upsert_budget( currency=currency, ).model_dump(exclude_none=True) response_data = self.make_request( - method="PUT", url_path=[APIConfig.LUNCHMONEY_BUDGET], payload=body + method=self.Methods.PUT, + url_path=[APIConfig.LUNCHMONEY_BUDGET], + payload=body, ) return response_data["category_group"] @@ -216,6 +219,8 @@ def remove_budget(self, start_date: datetime.date, category_id: int) -> bool: start_date=start_date, category_id=category_id ).model_dump() response_data = self.make_request( - method="DELETE", url_path=[APIConfig.LUNCHMONEY_BUDGET], params=params + method=self.Methods.DELETE, + url_path=[APIConfig.LUNCHMONEY_BUDGET], + params=params, ) return response_data diff --git a/lunchable/models/categories.py b/lunchable/models/categories.py index cd4557ee..2266738c 100644 --- a/lunchable/models/categories.py +++ b/lunchable/models/categories.py @@ -9,10 +9,9 @@ import logging from typing import List, Optional -from pydantic import Field - from lunchable._config import APIConfig from lunchable.exceptions import LunchMoneyError +from lunchable.models._base import LunchableField as Field from lunchable.models._base import LunchableModel from lunchable.models._core import LunchMoneyAPIClient diff --git a/lunchable/models/crypto.py b/lunchable/models/crypto.py index 24562087..c35d1d45 100644 --- a/lunchable/models/crypto.py +++ b/lunchable/models/crypto.py @@ -8,9 +8,8 @@ import logging from typing import List, Optional -from pydantic import Field - from lunchable._config import APIConfig +from lunchable.models._base import LunchableField as Field from lunchable.models._base import LunchableModel from lunchable.models._core import LunchMoneyAPIClient diff --git a/lunchable/models/plaid_accounts.py b/lunchable/models/plaid_accounts.py index b185210c..7e4f1870 100644 --- a/lunchable/models/plaid_accounts.py +++ b/lunchable/models/plaid_accounts.py @@ -8,9 +8,8 @@ import logging from typing import List, Optional -from pydantic import Field - from lunchable._config import APIConfig +from lunchable.models._base import LunchableField as Field from lunchable.models._base import LunchableModel from lunchable.models._core import LunchMoneyAPIClient diff --git a/lunchable/models/recurring_expenses.py b/lunchable/models/recurring_expenses.py index cfaff58c..898c4e71 100644 --- a/lunchable/models/recurring_expenses.py +++ b/lunchable/models/recurring_expenses.py @@ -8,9 +8,8 @@ import logging from typing import List, Optional -from pydantic import Field - from lunchable._config import APIConfig +from lunchable.models._base import LunchableField as Field from lunchable.models._base import LunchableModel from lunchable.models._core import LunchMoneyAPIClient @@ -159,7 +158,7 @@ def get_recurring_expenses( start_date=start_date, debit_as_negative=debit_as_negative ).model_dump() response_data = self.make_request( - method="GET", + method=self.Methods.GET, url_path=[APIConfig.LUNCH_MONEY_RECURRING_EXPENSES], params=params, ) diff --git a/lunchable/models/tags.py b/lunchable/models/tags.py index 22defdbb..fde127e2 100644 --- a/lunchable/models/tags.py +++ b/lunchable/models/tags.py @@ -7,9 +7,8 @@ import logging from typing import List, Optional -from pydantic import Field - from lunchable._config import APIConfig +from lunchable.models._base import LunchableField as Field from lunchable.models._base import LunchableModel from lunchable.models._core import LunchMoneyAPIClient diff --git a/lunchable/models/transactions.py b/lunchable/models/transactions.py index 8cbc1642..7c9dd417 100644 --- a/lunchable/models/transactions.py +++ b/lunchable/models/transactions.py @@ -9,10 +9,9 @@ from enum import Enum from typing import Any, Dict, List, Optional, Union -from pydantic import Field - from lunchable import LunchMoneyError from lunchable._config import APIConfig +from lunchable.models._base import LunchableField as Field from lunchable.models._base import LunchableModel from lunchable.models._core import LunchMoneyAPIClient from lunchable.models.tags import TagsObject @@ -512,13 +511,16 @@ def get_transactions( Examples -------- - Retrieve a list of :class:`.TransactionObject` :: + Retrieve a list of + [TransactionObject][lunchable.models.transactions.TransactionObject] - from lunchable import LunchMoney + ```python + from lunchable import LunchMoney - lunch = LunchMoney(access_token="xxxxxxx") - transactions = lunch.get_transactions(start_date="2020-01-01", - end_date="2020-01-31") + lunch = LunchMoney(access_token="xxxxxxx") + transactions = lunch.get_transactions(start_date="2020-01-01", + end_date="2020-01-31") + ``` """ search_params = _TransactionParamsGet( tag_id=tag_id, @@ -563,15 +565,18 @@ def get_transaction(self, transaction_id: int) -> TransactionObject: Examples -------- - Retrieve a single transaction by its ID :: + Retrieve a single transaction by its ID - from lunchable import LunchMoney + ```python + from lunchable import LunchMoney - lunch = LunchMoney(access_token="xxxxxxx") - transaction = lunch.get_transaction(transaction_id=1234) + lunch = LunchMoney(access_token="xxxxxxx") + transaction = lunch.get_transaction(transaction_id=1234) + ``` - The above code returns a :class:`.TransactionObject` with ID # 1234 (assuming - it exists) + The above code returns a + [TransactionObject][lunchable.models.transactions.TransactionObject] + with ID # 1234 (assuming it exists) """ response_data = self.make_request( method=self.Methods.GET, @@ -630,31 +635,38 @@ def update_transaction( Examples -------- - Update a transaction with a :class:`.TransactionUpdateObject` :: + Update a transaction with a + [TransactionUpdateObject][lunchable.models.transactions.TransactionUpdateObject] - from datetime import datetime + ```python + from datetime import datetime - from lunchable import LunchMoney, TransactionUpdateObject + from lunchable import LunchMoney, TransactionUpdateObject - lunch = LunchMoney(access_token="xxxxxxx") - transaction_note = f"Updated on {datetime.now()}" - notes_update = TransactionUpdateObject(notes=transaction_note) - response = lunch.update_transaction(transaction_id=1234, - transaction=notes_update) + lunch = LunchMoney(access_token="xxxxxxx") + transaction_note = f"Updated on {datetime.now()}" + notes_update = TransactionUpdateObject(notes=transaction_note) + response = lunch.update_transaction(transaction_id=1234, + transaction=notes_update) + ``` - Update a :class:`.TransactionObject` with itself :: + Update a + [TransactionObject][lunchable.models.transactions.TransactionObject] + with itself - from datetime import datetime, timedelta + ```python + from datetime import datetime, timedelta - from lunchable import LunchMoney + from lunchable import LunchMoney - lunch = LunchMoney(access_token="xxxxxxx") - transaction = lunch.get_transaction(transaction_id=1234) + lunch = LunchMoney(access_token="xxxxxxx") + transaction = lunch.get_transaction(transaction_id=1234) - transaction.notes = f"Updated on {datetime.now()}" - transaction.date = transaction.date + timedelta(days=1) - response = lunch.update_transaction(transaction_id=transaction.id, - transaction=transaction) + transaction.notes = f"Updated on {datetime.now()}" + transaction.date = transaction.date + timedelta(days=1) + response = lunch.update_transaction(transaction_id=transaction.id, + transaction=transaction) + ``` """ payload = _TransactionUpdateParamsPut( split=split, @@ -720,16 +732,19 @@ def insert_transactions( Examples -------- - Create a new transaction with a :class:`.TransactionInsertObject` :: + Create a new transaction with a + [TransactionInsertObject][lunchable.models.transactions.TransactionInsertObject] - from lunchable import LunchMoney, TransactionInsertObject + ```python + from lunchable import LunchMoney, TransactionInsertObject - lunch = LunchMoney(access_token="xxxxxxx") + lunch = LunchMoney(access_token="xxxxxxx") - new_transaction = TransactionInsertObject(payee="Example Restaurant", - amount=120.00, - notes="Saturday Dinner") - new_transaction_ids = lunch.insert_transactions(transactions=new_transaction) + new_transaction = TransactionInsertObject(payee="Example Restaurant", + amount=120.00, + notes="Saturday Dinner") + new_transaction_ids = lunch.insert_transactions(transactions=new_transaction) + ``` """ insert_objects = [] if not isinstance(transactions, list): diff --git a/lunchable/models/user.py b/lunchable/models/user.py index 6830368c..2bbf35b9 100644 --- a/lunchable/models/user.py +++ b/lunchable/models/user.py @@ -7,9 +7,8 @@ import logging from typing import Optional -from pydantic import Field - from lunchable._config import APIConfig +from lunchable.models._base import LunchableField as Field from lunchable.models._base import LunchableModel from lunchable.models._core import LunchMoneyAPIClient diff --git a/lunchable/plugins/base/base_app.py b/lunchable/plugins/base/base_app.py index 27735b99..03d656ab 100644 --- a/lunchable/plugins/base/base_app.py +++ b/lunchable/plugins/base/base_app.py @@ -320,6 +320,8 @@ def refresh_transactions( """ Refresh App data with the latest transactions + Parameters + ---------- start_date: Optional[Union[datetime.date, datetime.datetime, str]] Denotes the beginning of the time period to fetch transactions for. Defaults to beginning of current month. Required if end_date exists. Format: YYYY-MM-DD. diff --git a/lunchable/plugins/primelunch/primelunch.py b/lunchable/plugins/primelunch/primelunch.py index c3492ab6..90679cd3 100644 --- a/lunchable/plugins/primelunch/primelunch.py +++ b/lunchable/plugins/primelunch/primelunch.py @@ -18,9 +18,13 @@ from rich import print, table from rich.prompt import Confirm -from lunchable import TransactionUpdateObject from lunchable._config.logging_config import set_up_logging -from lunchable.models import CategoriesObject, TransactionObject, UserObject +from lunchable.models import ( + CategoriesObject, + TransactionObject, + TransactionUpdateObject, + UserObject, +) from lunchable.plugins.base.pandas_app import LunchablePandasApp logger = logging.getLogger(__name__) diff --git a/lunchable/plugins/splitlunch/lunchmoney_splitwise.py b/lunchable/plugins/splitlunch/lunchmoney_splitwise.py index 94b56b1c..ddfeff7a 100644 --- a/lunchable/plugins/splitlunch/lunchmoney_splitwise.py +++ b/lunchable/plugins/splitlunch/lunchmoney_splitwise.py @@ -72,75 +72,6 @@ def _get_splitwise_impact( class SplitLunch(splitwise.Splitwise): """ Lunchable Plugin For Interacting With Splitwise - - This plugin supports different operations, and some of those operations - have prerequisites: - - 1) It supports the auto-importing of Splitwise expenses into Lunch Money - transactions. This requires a manual asset exist in your Lunch Money - account with "Splitwise" in the Name. - - Prerequisites: - - Accounts: - - Splitwise must be in the account name - - 2) It supports the creation of Splitwise transactions directly from synced Lunch Money - accounts. This syncing requires you create a tag called `SplitLunchImport`. Transactions - with this tag will be created in Splitwise with your "financial partner". Once transactions - are created in Splitwise they will be split in half in Lunch Money. Half of the split will be - marked in the `Reimbursement` category which must be created. - - Prerequisites: - - Financial Partners: - - If you only have one friend in Splitwise, this is your Financial Partner - - Financial Partners must be specified by their Splitwise ID or Email Address - - Tags: - - `SplitLunchImport` - - Categories: - - `Reimbursement` - - 3) It supports a workflow where you mark transactions as split (identical to scenario #2) - without importing them into Splitwise. This syncing requires you create a tag - called `SplitLunch` and a category named `Reimbursement` - - Prerequisites: - - Tags: - - `SplitLunch` - - Categories: - - `Reimbursement` - - 4) It supports a workflow where you mark transactions as `Reimbursed` and import them to - Splitwise with the total completely owed by your financial partner. - - Prerequisites: - - Financial Partners: - - If you only have one friend in Splitwise, this is your Financial Partner - - Financial Partners must be specified by their Splitwise ID or Email Address - - Tags: - - `SplitLunchDirectImport` - - Categories: - - `Reimbursement` - - Parameters - ---------- - financial_partner_id: Optional[int] - Splitwise User ID of financial partner - financial_partner_email: Optional[str] - Splitwise linked email address of financial partner - financial_partner_group_id: Optional[int] - Splitwise Group ID for financial partner transactions - consumer_key: Optional[str] - Consumer Key provided by Splitwise. Defaults to `SPLITWISE_CONSUMER_KEY` environment - variable - consumer_secret: Optional[str] - Consumer Key provided by Splitwise. Defaults to `SPLITWISE_CONSUMER_SECRET` - environment variable - api_key: Optional[str] - Consumer Key provided by Splitwise. Defaults to `SPLITWISE_API_KEY` environment - variable. - lunchable_client: LunchMoney - Instantiated LunchMoney object to use as internal client. One will - be created using environment variables otherwise. """ def __init__( diff --git a/mkdocs.yaml b/mkdocs.yaml new file mode 100644 index 00000000..7916f84b --- /dev/null +++ b/mkdocs.yaml @@ -0,0 +1,86 @@ +# $schema: https://squidfunk.github.io/mkdocs-material/schema.json + +site_name: lunchable +nav: +- Home 🏠: index.md +- Usage 📖: usage.md +- LunchMoney 🍽️: interacting.md +- Plugins 🧩: + - plugins/index.md + - PushLunch 📲: plugins/pushlunch.md + - SplitLunch 🍱: plugins/splitlunch.md + - PrimeLunch 🥪: plugins/primelunch.md +- Command Line Interface ⌨️: cli.md +- API Documentation 🤖: reference/ +- Contributing 🤝: contributing.md +theme: + favicon: https://juftin.com/favicon.ico + logo: https://raw.githubusercontent.com/juftin/juftin/main/static/juftin.png + name: material + features: + - navigation.tracking + - content.code.annotate + - content.code.copy + - navigation.indexes + palette: + - media: '(prefers-color-scheme: light)' + scheme: default + accent: purple + toggle: + icon: material/weather-sunny + name: Switch to dark mode + - media: '(prefers-color-scheme: dark)' + scheme: slate + primary: black + toggle: + icon: material/weather-night + name: Switch to light mode +repo_url: https://github.com/juftin/lunchable +repo_name: lunchable +edit_uri: blob/main/docs/ +site_author: juftin +remote_branch: gh-pages +#copyright: Copyright © 2023 Justin Flannery +extra: + generator: false +markdown_extensions: +- toc: + permalink: '#' +- pymdownx.snippets: +- pymdownx.magiclink +- attr_list +- md_in_html +- pymdownx.highlight: + anchor_linenums: true +- pymdownx.inlinehilite +- pymdownx.superfences +- markdown.extensions.attr_list +- pymdownx.keys +- pymdownx.tasklist +- pymdownx.tilde +- callouts +- pymdownx.details +- pymdownx.emoji +- pymdownx.tabbed: + alternate_style: true +- mkdocs-click: +plugins: +- search +- markdown-exec +- section-index +- autorefs +- mkdocstrings: + handlers: + python: + import: + - https://docs.python.org/3/objects.inv + - https://pandas.pydata.org/docs/objects.inv + options: + docstring_style: numpy + extensions: + - griffe_fieldz +- gen-files: + scripts: + - docs/gen_pages.py +- literate-nav: + nav_file: SUMMARY.md diff --git a/pyproject.toml b/pyproject.toml index 828c3e0f..3a42f547 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -81,7 +81,10 @@ parallel = true source_pkgs = ["lunchable", "tests"] [tool.hatch.env] -requires = ["hatch-pip-compile"] +requires = ["hatch-pip-compile", "hatch-mkdocs"] + +[tool.hatch.env.collectors.mkdocs.docs] +path = "mkdocs.yaml" [tool.hatch.envs.all] pip-compile-constraint = "" @@ -103,30 +106,11 @@ cov = "hatch run test:cov {args:}" test = "hatch run test:test {args:}" [tool.hatch.envs.docs] -dependencies = [ - "sphinx", - "sphinx-rtd-theme", - "autodocsumm", - "myst-parser[linkify]", - "autoclasstoc", - "sphinx-copybutton", - "sphinx_autodoc_defaultargs", - "sphinxcontrib-apidoc", - "sphinx-click", - "sphinx-autodoc-typehints", - "autodoc_pydantic" -] - -[tool.hatch.envs.docs.scripts] -build = [ - "rm -rf docs/_build/ && rm -rf docs/source/api/", - "cd docs && make html" -] -deploy = ["mkdocs gh-deploy {args:}"] -serve = [ - "build", - "python -m http.server --bind 0.0.0.0 -d docs/_build/html/" +detached = false +extra-dependencies = [ + "griffe-fieldz" ] +type = "pip-compile" [tool.hatch.envs.gen] detached = true diff --git a/requirements/requirements-docs.txt b/requirements/requirements-docs.txt index ec9a4db9..520a3b7a 100644 --- a/requirements/requirements-docs.txt +++ b/requirements/requirements-docs.txt @@ -3,17 +3,19 @@ # # [constraints] requirements.txt (SHA256: 1d7f43c7c1ecbc074ece84ddfddf590007473fce44e813c9dca4481292391f67) # -# - sphinx -# - sphinx-rtd-theme -# - autodocsumm -# - myst-parser[linkify] -# - autoclasstoc -# - sphinx-copybutton -# - sphinx_autodoc_defaultargs -# - sphinxcontrib-apidoc -# - sphinx-click -# - sphinx-autodoc-typehints -# - autodoc_pydantic +# - markdown-callouts +# - markdown-exec +# - mkdocs +# - mkdocs-autorefs +# - mkdocs-click +# - mkdocs-gen-files +# - mkdocs-literate-nav +# - mkdocs-material +# - mkdocs-section-index +# - mkdocstrings +# - mkdocstrings-python +# - pymdown-extensions +# - griffe-fieldz # - click>=8.0.1 # - httpx # - pydantic<3,>=2 @@ -23,8 +25,6 @@ # - splitwise<3.0.0,>=2.3.0 # -alabaster==0.7.13 - # via sphinx annotated-types==0.6.0 # via # -c requirements.txt @@ -33,14 +33,8 @@ anyio==4.1.0 # via # -c requirements.txt # httpx -autoclasstoc==1.6.0 - # via hatch.envs.docs -autodoc-pydantic==2.0.1 - # via hatch.envs.docs -autodocsumm==0.2.11 - # via hatch.envs.docs babel==2.14.0 - # via sphinx + # via mkdocs-material certifi==2023.11.17 # via # -c requirements.txt @@ -55,14 +49,23 @@ click==8.1.7 # via # -c requirements.txt # hatch.envs.docs - # sphinx-click -docutils==0.20.1 - # via - # autoclasstoc - # myst-parser - # sphinx - # sphinx-click - # sphinx-rtd-theme + # mkdocs + # mkdocs-click + # mkdocstrings +colorama==0.4.6 + # via + # griffe + # mkdocs-material +fieldz==0.0.2 + # via griffe-fieldz +ghp-import==2.1.0 + # via mkdocs +griffe==0.38.1 + # via + # griffe-fieldz + # mkdocstrings-python +griffe-fieldz==0.1.1 + # via hatch.envs.docs h11==0.14.0 # via # -c requirements.txt @@ -81,31 +84,69 @@ idna==3.6 # anyio # httpx # requests -imagesize==1.4.1 - # via sphinx jinja2==3.1.2 # via - # myst-parser - # sphinx -linkify-it-py==2.0.2 - # via myst-parser + # mkdocs + # mkdocs-material + # mkdocstrings +markdown==3.5.1 + # via + # markdown-callouts + # mkdocs + # mkdocs-autorefs + # mkdocs-click + # mkdocs-material + # mkdocstrings + # pymdown-extensions +markdown-callouts==0.3.0 + # via hatch.envs.docs +markdown-exec==1.7.0 + # via hatch.envs.docs markdown-it-py==3.0.0 # via # -c requirements.txt - # mdit-py-plugins - # myst-parser # rich markupsafe==2.1.3 - # via jinja2 -mdit-py-plugins==0.4.0 - # via myst-parser + # via + # jinja2 + # mkdocs + # mkdocstrings mdurl==0.1.2 # via # -c requirements.txt # markdown-it-py -more-itertools==10.1.0 - # via autoclasstoc -myst-parser==2.0.0 +mergedeep==1.3.4 + # via mkdocs +mkdocs==1.5.3 + # via + # hatch.envs.docs + # mkdocs-autorefs + # mkdocs-gen-files + # mkdocs-literate-nav + # mkdocs-material + # mkdocs-section-index + # mkdocstrings +mkdocs-autorefs==0.5.0 + # via + # hatch.envs.docs + # mkdocstrings +mkdocs-click==0.8.1 + # via hatch.envs.docs +mkdocs-gen-files==0.5.0 + # via hatch.envs.docs +mkdocs-literate-nav==0.6.1 + # via hatch.envs.docs +mkdocs-material==9.5.2 + # via hatch.envs.docs +mkdocs-material-extensions==1.3.1 + # via mkdocs-material +mkdocs-section-index==0.3.8 + # via hatch.envs.docs +mkdocstrings==0.24.0 + # via + # hatch.envs.docs + # mkdocstrings-python +mkdocstrings-python==1.7.5 # via hatch.envs.docs numpy==1.26.2 # via @@ -116,48 +157,62 @@ oauthlib==3.2.2 # -c requirements.txt # requests-oauthlib packaging==23.2 - # via sphinx + # via mkdocs +paginate==0.5.6 + # via mkdocs-material pandas==2.1.4 # via # -c requirements.txt # hatch.envs.docs -pbr==6.0.0 - # via sphinxcontrib-apidoc +pathspec==0.12.1 + # via mkdocs +platformdirs==4.1.0 + # via + # mkdocs + # mkdocstrings pydantic==2.5.2 # via # -c requirements.txt # hatch.envs.docs - # autodoc-pydantic - # pydantic-settings pydantic-core==2.14.5 # via # -c requirements.txt # pydantic -pydantic-settings==2.1.0 - # via autodoc-pydantic pygments==2.17.2 # via # -c requirements.txt + # mkdocs-material # rich - # sphinx +pymdown-extensions==10.5 + # via + # hatch.envs.docs + # markdown-exec + # mkdocs-material + # mkdocstrings python-dateutil==2.8.2 # via # -c requirements.txt # hatch.envs.docs + # ghp-import # pandas -python-dotenv==1.0.0 - # via pydantic-settings pytz==2023.3.post1 # via # -c requirements.txt # pandas pyyaml==6.0.1 - # via myst-parser + # via + # mkdocs + # pymdown-extensions + # pyyaml-env-tag +pyyaml-env-tag==0.1 + # via mkdocs +regex==2023.10.3 + # via mkdocs-material requests==2.31.0 # via # -c requirements.txt + # mkdocs-material # requests-oauthlib - # sphinx # splitwise requests-oauthlib==1.3.1 # via @@ -176,53 +231,6 @@ sniffio==1.3.0 # -c requirements.txt # anyio # httpx -snowballstemmer==2.2.0 - # via sphinx -sphinx==7.2.6 - # via - # hatch.envs.docs - # autoclasstoc - # autodoc-pydantic - # autodocsumm - # myst-parser - # sphinx-autodoc-defaultargs - # sphinx-autodoc-typehints - # sphinx-click - # sphinx-copybutton - # sphinx-rtd-theme - # sphinxcontrib-apidoc - # sphinxcontrib-applehelp - # sphinxcontrib-devhelp - # sphinxcontrib-htmlhelp - # sphinxcontrib-jquery - # sphinxcontrib-qthelp - # sphinxcontrib-serializinghtml -sphinx-autodoc-defaultargs==0.1.2 - # via hatch.envs.docs -sphinx-autodoc-typehints==1.25.2 - # via hatch.envs.docs -sphinx-click==5.1.0 - # via hatch.envs.docs -sphinx-copybutton==0.5.2 - # via hatch.envs.docs -sphinx-rtd-theme==2.0.0 - # via hatch.envs.docs -sphinxcontrib-apidoc==0.4.0 - # via hatch.envs.docs -sphinxcontrib-applehelp==1.0.7 - # via sphinx -sphinxcontrib-devhelp==1.0.5 - # via sphinx -sphinxcontrib-htmlhelp==2.0.4 - # via sphinx -sphinxcontrib-jquery==4.1 - # via sphinx-rtd-theme -sphinxcontrib-jsmath==1.0.1 - # via sphinx -sphinxcontrib-qthelp==1.0.6 - # via sphinx -sphinxcontrib-serializinghtml==1.1.9 - # via sphinx splitwise==2.5.0 # via # -c requirements.txt @@ -230,15 +238,16 @@ splitwise==2.5.0 typing-extensions==4.9.0 # via # -c requirements.txt + # fieldz # pydantic # pydantic-core tzdata==2023.3 # via # -c requirements.txt # pandas -uc-micro-py==1.0.2 - # via linkify-it-py urllib3==2.1.0 # via # -c requirements.txt # requests +watchdog==3.0.0 + # via mkdocs