From 836d13d0233c886fbb8ee2158e38c3647ead125f Mon Sep 17 00:00:00 2001 From: juftin Date: Fri, 15 Dec 2023 21:44:09 -0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=A5=20httpx=20refactor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit replaces requests with httpx. Breaking API Changes: - `LunchMoney.make_http_request()` -> `LunchMoney.request()` - `LunchMoney.lunchmoney_session` -> `LunchMoney.session` Other API Changes: - `LunchMoney._make_request()` -> `LunchMoney.make_request()` - `LunchMoney.process_response()` - handle a raw response - `LunchMoney.async_session` - async session - `LunchMoney.arequest()` - raw async requests - `LunchMoney.process_response()` - handle a raw response --- README.md | 5 +- docs/source/index.rst | 3 +- lunchable/_cli.py | 34 +- lunchable/_config/api_config.py | 12 +- lunchable/_config/logging_config.py | 5 + lunchable/exceptions.py | 2 +- lunchable/models/_core.py | 347 +++++++++++++----- lunchable/models/assets.py | 6 +- lunchable/models/budgets.py | 6 +- lunchable/models/categories.py | 16 +- lunchable/models/crypto.py | 4 +- lunchable/models/plaid_accounts.py | 2 +- lunchable/models/recurring_expenses.py | 2 +- lunchable/models/tags.py | 2 +- lunchable/models/transactions.py | 14 +- lunchable/models/user.py | 2 +- lunchable/plugins/pushlunch/pushover.py | 8 +- pyproject.toml | 10 +- requirements.txt | 25 +- requirements/requirements-all.py3.10.txt | 26 +- requirements/requirements-all.py3.11.txt | 22 +- requirements/requirements-all.py3.12.txt | 22 +- requirements/requirements-all.py3.8.txt | 26 +- requirements/requirements-all.py3.9.txt | 26 +- requirements/requirements-docs.txt | 124 ++++++- requirements/requirements-lint.txt | 2 +- requirements/requirements-test.txt | 30 +- tests/conftest.py | 1 - .../cassettes/test_add_to_category_group.yaml | 8 +- ...t_create_and_delete_transaction_group.yaml | 16 +- tests/models/cassettes/test_create_asset.yaml | 8 +- .../cassettes/test_create_category.yaml | 8 +- .../cassettes/test_create_category_group.yaml | 8 +- .../models/cassettes/test_delete_budget.yaml | 8 +- .../cassettes/test_delete_category.yaml | 8 +- .../cassettes/test_delete_category_force.yaml | 8 +- tests/models/cassettes/test_get_assets.yaml | 8 +- tests/models/cassettes/test_get_budgets.yaml | 8 +- .../models/cassettes/test_get_categories.yaml | 8 +- tests/models/cassettes/test_get_category.yaml | 8 +- tests/models/cassettes/test_get_crypto.yaml | 8 +- .../cassettes/test_get_plaid_accounts.yaml | 50 +-- .../test_get_recurring_expenses.yaml | 10 +- tests/models/cassettes/test_get_tags.yaml | 8 +- .../cassettes/test_get_transaction.yaml | 8 +- .../cassettes/test_get_transactions.yaml | 8 +- .../test_get_uncleared_transactions.yaml | 54 +++ tests/models/cassettes/test_get_user.yaml | 8 +- .../cassettes/test_insert_transactions.yaml | 8 +- .../cassettes/test_split_transaction.yaml | 16 +- .../cassettes/test_unsplit_transaction.yaml | 8 +- tests/models/cassettes/test_update_asset.yaml | 8 +- .../cassettes/test_update_category.yaml | 8 +- .../models/cassettes/test_update_crypto.yaml | 8 +- .../cassettes/test_update_transaction.yaml | 8 +- .../models/cassettes/test_upsert_budget.yaml | 8 +- tests/models/test_transactions.py | 13 + .../cassettes/test_post_transaction.yaml | 74 +--- .../cassettes/test_send_notification.yaml | 74 +--- .../cassettes/test_update_balance.yaml | 43 +-- 60 files changed, 788 insertions(+), 530 deletions(-) create mode 100644 tests/models/cassettes/test_get_uncleared_transactions.yaml diff --git a/README.md b/README.md index 0f2d537a..4f2a1c0f 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,9 @@ [![GitHub License](https://img.shields.io/github/license/juftin/lunchable?color=blue&label=License)](https://github.com/juftin/lunchable/blob/main/LICENSE) **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), it offers an _intuitive_ API, -a _simple_ CLI, complete coverage of all endpoints, and _plugins_ to other external services. +built on top of [pydantic](https://github.com/pydantic/pydantic) and [httpx](https://github.com/encode/httpx/), +it offers an _intuitive_ API, a _simple_ CLI, complete coverage of all endpoints, +and _plugins_ to other external services. ### Installation diff --git a/docs/source/index.rst b/docs/source/index.rst index a9fc2bd0..56d1fbd3 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -9,7 +9,8 @@ **lunchable** is a Python Client for the `Lunch Money Developer API `_. -It's built on top of `pydantic `_, +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 diff --git a/lunchable/_cli.py b/lunchable/_cli.py index b36ec172..49ad0078 100644 --- a/lunchable/_cli.py +++ b/lunchable/_cli.py @@ -9,8 +9,8 @@ from typing import Any, Dict, Optional, Union import click -import requests -from pydantic.json import pydantic_encoder +import httpx +from pydantic_core import to_jsonable_python from rich import print, print_json, traceback import lunchable @@ -145,7 +145,8 @@ def lunchmoney_transactions( """ lunch = LunchMoney(access_token=context.access_token) transactions = lunch.get_transactions(**kwargs) # type: ignore[arg-type] - print_json(data=transactions, default=pydantic_encoder) + json_data = to_jsonable_python(transactions) + print_json(data=json_data) @plugins.group() @@ -198,7 +199,8 @@ def splitlunch_expenses(**kwargs: Union[int, str, bool]) -> None: if set(kwargs.values()) == {None}: kwargs["limit"] = 5 expenses = splitlunch.get_expenses(**kwargs) # type: ignore[arg-type] - print_json(data=expenses, default=pydantic_encoder) + json_data = to_jsonable_python(expenses) + print_json(data=json_data) tag_transactions = click.option( @@ -237,7 +239,8 @@ def make_splitlunch(**kwargs: Union[int, str, bool]) -> None: splitlunch = SplitLunch() results = splitlunch.make_splitlunch(**kwargs) # type: ignore[arg-type] - print_json(data=results, default=pydantic_encoder) + json_data = to_jsonable_python(results) + print_json(data=json_data) @splitlunch.command("splitlunch-import") @@ -264,7 +267,8 @@ def make_splitlunch_import(**kwargs: Union[int, str, bool]) -> None: financial_partner_group_id=financial_partner_group_id, ) results = splitlunch.make_splitlunch_import(**kwargs) # type: ignore[arg-type] - print_json(data=results, default=pydantic_encoder) + json_data = to_jsonable_python(results) + print_json(data=json_data) @splitlunch.command("splitlunch-direct-import") @@ -291,7 +295,8 @@ def make_splitlunch_direct_import(**kwargs: Union[int, str, bool]) -> None: financial_partner_group_id=financial_partner_group_id, ) results = splitlunch.make_splitlunch_direct_import(**kwargs) # type: ignore[arg-type] - print_json(data=results, default=pydantic_encoder) + json_data = to_jsonable_python(results) + print_json(data=json_data) @splitlunch.command("update-balance") @@ -303,7 +308,8 @@ def update_splitwise_balance() -> None: splitlunch = SplitLunch() updated_asset = splitlunch.update_splitwise_balance() - print_json(data=updated_asset, default=pydantic_encoder) + json_data = to_jsonable_python(updated_asset) + print_json(data=json_data) @splitlunch.command("refresh") @@ -341,7 +347,8 @@ def refresh_splitwise_transactions( allow_self_paid=allow_self_paid, allow_payments=allow_payments, ) - print_json(data=response, default=pydantic_encoder) + json_data = to_jsonable_python(response) + print_json(data=json_data) @plugins.group() @@ -397,14 +404,14 @@ def http(context: LunchMoneyContext, url: str, request: str, data: str) -> None: url_request = f"https://dev.lunchmoney.app/{url}" else: url_request = url - resp = lunch.make_http_request( + resp = lunch.request( method=request, url=url_request, - data=data, + content=data, ) try: resp.raise_for_status() - except requests.HTTPError: + except httpx.HTTPError: logger.error(resp) print(resp.text) sys.exit(1) @@ -412,7 +419,8 @@ def http(context: LunchMoneyContext, url: str, request: str, data: str) -> None: response = resp.json() except JSONDecodeError: response = resp.text - print_json(data=response, default=pydantic_encoder) + json_data = to_jsonable_python(response) + print_json(data=json_data) @plugins.group() diff --git a/lunchable/_config/api_config.py b/lunchable/_config/api_config.py index 81ae10e8..c0c29db5 100644 --- a/lunchable/_config/api_config.py +++ b/lunchable/_config/api_config.py @@ -7,6 +7,7 @@ from typing import Dict, List, Optional, Union from urllib import parse +from lunchable._version import __version__ from lunchable.exceptions import EnvironmentVariableError, LunchMoneyError logger = logging.getLogger(__name__) @@ -69,7 +70,7 @@ def get_access_token(access_token: Optional[str] = None) -> str: @staticmethod def get_header(access_token: Optional[str] = None) -> Dict[str, str]: """ - Get the header dict to pass to requests + Get the header dict to pass to httpx Parameters ---------- @@ -81,9 +82,12 @@ def get_header(access_token: Optional[str] = None) -> Dict[str, str]: Dict[str, str] """ access_token = APIConfig.get_access_token(access_token=access_token) - auth_header = {"Authorization": f"Bearer {access_token}"} - auth_header.update(APIConfig.LUNCHMONEY_CONTENT_TYPE_HEADERS) - return auth_header + lunchable_header = { + "Authorization": f"Bearer {access_token}", + "User-Agent": f"lunchable/{__version__}", + } + lunchable_header.update(APIConfig.LUNCHMONEY_CONTENT_TYPE_HEADERS) + return lunchable_header @staticmethod def make_url(url_path: Union[List[Union[str, int]], str, int]) -> str: diff --git a/lunchable/_config/logging_config.py b/lunchable/_config/logging_config.py index cc346a24..853e903c 100644 --- a/lunchable/_config/logging_config.py +++ b/lunchable/_config/logging_config.py @@ -7,6 +7,7 @@ from typing import Optional, Tuple, Union import click +from rich.console import Console from rich.logging import RichHandler LOG_HANDLER = getenv("LOG_HANDLER", "rich").lower() @@ -36,7 +37,11 @@ def get_log_handler( omit_repeated_times=False, show_path=False, tracebacks_suppress=[click], + console=Console(stderr=True), ) + httpx_logger = logging.getLogger("httpx") + if log_level != logging.DEBUG: + httpx_logger.setLevel(logging.WARNING) python_handler = logging.StreamHandler() python_formatter = logging.Formatter("%(asctime)s [%(levelname)8s]: %(message)s") python_handler.setFormatter(python_formatter) diff --git a/lunchable/exceptions.py b/lunchable/exceptions.py index 1636651b..6e360b80 100644 --- a/lunchable/exceptions.py +++ b/lunchable/exceptions.py @@ -2,7 +2,7 @@ Lunchmoney Exceptions """ -from requests.exceptions import HTTPError +from httpx import HTTPError class LunchMoneyError(Exception): diff --git a/lunchable/models/_core.py b/lunchable/models/_core.py index 74105f4c..236b2ff6 100644 --- a/lunchable/models/_core.py +++ b/lunchable/models/_core.py @@ -2,13 +2,22 @@ Lunchmoney SDK Core """ -import datetime -import json +from __future__ import annotations + import logging -from json import loads -from typing import Any, Dict, List, Optional, Union +from functools import cached_property +from typing import ( + Any, + AsyncIterable, + Iterable, + Mapping, + Optional, + Union, +) -import requests +import httpx +import pydantic_core +from httpx import Client from lunchable._config import APIConfig from lunchable.exceptions import LunchMoneyHTTPError @@ -16,15 +25,26 @@ logger = logging.getLogger(__name__) -class _Methods: +class LunchMoneyClient(Client): """ - Namespace for Request Methods + API HTTP Client """ - GET = "GET" - POST = "POST" - PUT = "PUT" - DELETE = "DELETE" + def __init__(self, access_token: str | None = None) -> None: + super().__init__() + api_headers = APIConfig.get_header(access_token=access_token) + self.headers.update(api_headers) + + +class LunchMoneyAsyncClient(httpx.AsyncClient): + """ + API Async HTTP Client + """ + + def __init__(self, access_token: str | None = None) -> None: + super().__init__() + api_headers = APIConfig.get_header(access_token=access_token) + self.headers.update(api_headers) class LunchMoneyAPIClient: @@ -46,7 +66,7 @@ class Methods: PATCH = "PATCH" DELETE = "DELETE" - def __init__(self, access_token: Optional[str] = None): + def __init__(self, access_token: str | None = None) -> None: """ Initialize a Lunch Money object with an Access Token. @@ -58,12 +78,6 @@ def __init__(self, access_token: Optional[str] = None): Lunchmoney Developer API Access Token """ self.access_token = APIConfig.get_access_token(access_token=access_token) - api_headers = APIConfig.get_header(access_token=self.access_token) - default_headers = requests.sessions.default_headers() - updated_headers = dict(**default_headers, **api_headers) - typed_headers = requests.models.CaseInsensitiveDict(updated_headers) - self.lunch_money_session = requests.Session() - self.lunch_money_session.headers = typed_headers # type: ignore[assignment] def __repr__(self) -> str: """ @@ -73,83 +87,48 @@ def __repr__(self) -> str: ------- str """ - return "" + return "" - @staticmethod - def _serializer(obj: Any) -> str: - if isinstance(obj, datetime.datetime): - return obj.isoformat() - elif isinstance(obj, datetime.date): - return obj.isoformat() - else: - return obj + @cached_property + def session(self) -> httpx.Client: + """ + Lunch Money HTTPX Client - def _make_request( - self, - method: str, - url_path: Union[List[Union[str, int]], str, int], - params: Optional[Dict[str, Any]] = None, - payload: Optional[Any] = None, - **kwargs: Any, - ) -> Any: + Returns + ------- + httpx.Client """ - Make a Request to the API + return LunchMoneyClient(access_token=self.access_token) - Parameters - ---------- - method: str - requests method: GET, OPTIONS, HEAD, POST, PUT, - PATCH, or DELETE - url_path: Union[List[Union[str, int]], str, int] - API Components, if a list join these sequentially - params: Optional[Dict[str, Any]] - Params to pass - payload: Optional[Any] - data to pass + @cached_property + def async_session(self) -> httpx.AsyncClient: + """ + Lunch Money HTTPX Async Client Returns ------- - Any + httpx.AsyncClient """ - url = APIConfig.make_url(url_path=url_path) - if payload is not None: - payload = json.dumps(payload, default=LunchMoneyAPIClient._serializer) - try: - response = self.lunch_money_session.request( - method=method, url=url, params=params, data=payload, **kwargs - ) - response.raise_for_status() - except requests.exceptions.HTTPError as he: - logger.exception(he) - # noinspection PyUnboundLocalVariable - logger.error(response.text) - raise LunchMoneyHTTPError(he) from he - returned_data = loads(response.content) - if isinstance(returned_data, dict) and any( - ["error" in returned_data.keys(), "errors" in returned_data.keys()] - ): - try: - errors = returned_data["error"] - except KeyError: - errors = returned_data["errors"] - logger.exception(errors) - raise LunchMoneyHTTPError(errors) - return loads(response.content) + return LunchMoneyAsyncClient(access_token=self.access_token) - def make_http_request( + def request( self, method: str, - url: str, - params: Optional[Any] = None, - data: Optional[Any] = None, + url: Union[httpx.URL, str], + *, + content: Optional[ + Union[str, bytes, Iterable[bytes], AsyncIterable[bytes]] + ] = None, + data: Optional[Mapping[str, Any]] = None, json: Optional[Any] = None, + params: Optional[Mapping[str, Any]] = None, **kwargs: Any, - ) -> requests.Response: + ) -> httpx.Response: """ - Make a HTTP Request + Make an HTTP Request This is a simple method :class:`.LunchMoney` exposes to make HTTP requests. It - has the benefit of using an existing `requests.Session` as well as as out of the box + has the benefit of using an existing `httpx.Client` as well as as out of the box auth headers that are used to connect to the Lunch Money Developer API. Parameters @@ -157,20 +136,24 @@ def make_http_request( method: str requests method: GET, OPTIONS, HEAD, POST, PUT, PATCH, or DELETE - url: str + url: Union[httpx.URL, str] URL for the new Request object. - params: Optional[Any] - Dictionary, list of tuples or bytes to send in the query - string for the Request. - data: Optional[Any] + content: Optional[Union[str, bytes, Iterable[bytes], AsyncIterable[bytes]]] + Content to send in the body of the Request. + data: Optional[Mapping[str, Any]] Dictionary, list of tuples, bytes, or file-like object to send in the body of the Request. json: Optional[Any] A JSON serializable Python object to send in the body of the Request. + params: Optional[Mapping[str, Any]] + Dictionary, list of tuples or bytes to send in the query + string for the Request. + **kwargs: Any + Additional arguments to send to the request method. Returns ------- - Any + httpx.Response Examples -------- @@ -190,15 +173,201 @@ def make_http_request( cookies = {"cookie_keys": "cookie_values"} for null_tag in null_tags: - # use the requests.session embedded in the class to make a request with cookies - response = lunch.make_request( + # 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() """ - response = self.lunch_money_session.request( - method=method, url=url, params=params, data=data, json=json, **kwargs + response = self.session.request( + method=method, + url=url, + content=content, + data=data, + json=json, + params=params, + **kwargs, ) return response + + async def arequest( + self, + method: str, + url: Union[httpx.URL, str], + *, + content: Optional[ + Union[str, bytes, Iterable[bytes], AsyncIterable[bytes]] + ] = None, + data: Optional[Mapping[str, Any]] = None, + json: Optional[Any] = None, + params: Optional[Mapping[str, Any]] = None, + **kwargs: Any, + ) -> httpx.Response: + """ + Make an async HTTP Request + + This is a simple method :class:`.LunchMoney` exposes to make HTTP requests. It + has the benefit of using an existing `httpx.Client` as well as as out of the box + auth headers that are used to connect to the Lunch Money Developer API. + + Parameters + ---------- + method: str + requests method: GET, OPTIONS, HEAD, POST, PUT, + PATCH, or DELETE + url: Union[httpx.URL, str] + URL for the new Request object. + content: Optional[Union[str, bytes, Iterable[bytes], AsyncIterable[bytes]]] + Content to send in the body of the Request. + data: Optional[Mapping[str, Any]] + Dictionary, list of tuples, bytes, or file-like object to send + in the body of the Request. + json: Optional[Any] + A JSON serializable Python object to send in the body of the Request. + params: Optional[Mapping[str, Any]] + Dictionary, list of tuples or bytes to send in the query + string for the Request. + **kwargs: Any + Additional arguments to send to the request method. + + Returns + ------- + httpx.Response + """ + response = self.async_session.request( + method=method, + url=url, + content=content, + data=data, + json=json, + params=params, + **kwargs, + ) + return await response + + @classmethod + def process_response(cls, response: httpx.Response) -> Any: + """ + Process a Lunch Money Response + + This includes 200 responses that are actually errors + + Parameters + ---------- + response: httpx.Response + An HTTPX Response Object + """ + try: + response.raise_for_status() + except httpx.HTTPError as he: + logger.exception(he) + logger.error(response.text) + raise LunchMoneyHTTPError(response.text) from he + if response.content: + returned_data = response.json() + else: + returned_data = None + if isinstance(returned_data, dict) and any( + ["error" in returned_data.keys(), "errors" in returned_data.keys()] + ): + try: + errors = returned_data["error"] + except KeyError: + errors = returned_data["errors"] + logger.exception(errors) + raise LunchMoneyHTTPError(errors) + return returned_data + + def make_request( + self, + method: str, + url_path: Union[list[Union[str, int]], str, int], + params: Optional[Mapping[str, Any]] = None, + payload: Optional[Any] = None, + **kwargs: Any, + ) -> Any: + """ + Make an HTTP Request and return its data + + This method is a wrapper around :meth:`.LunchMoney.request` that + also processes the response and checks for any errors. + + Parameters + ---------- + method: str + requests method: GET, OPTIONS, HEAD, POST, PUT, + PATCH, or DELETE + url_path: Union[List[Union[str, int]], str, int] + URL components to make into a URL + payload: Optional[Mapping[str, Any]] + Data to send in the body of the Request. + params: Optional[Mapping[str, Any]] + Dictionary, list of tuples or bytes to send in the query + string for the Request. + **kwargs: Any + Additional arguments to send to the request method. + + Returns + ------- + Any + """ + url = APIConfig.make_url(url_path=url_path) + json_safe_payload = pydantic_core.to_jsonable_python(payload) + json_safe_params = pydantic_core.to_jsonable_python(params) + response = self.request( + method=method, + url=url, + params=json_safe_params, + data=json_safe_payload, + **kwargs, + ) + data = self.process_response(response=response) + return data + + async def amake_request( + self, + method: str, + url_path: Union[list[Union[str, int]], str, int], + params: Optional[Mapping[str, Any]] = None, + payload: Optional[Any] = None, + **kwargs: Any, + ) -> Any: + """ + Make an async HTTP Request and return its data + + This method is a wrapper around :meth:`.LunchMoney.arequest` that + also processes the response and checks for any errors. + + Parameters + ---------- + method: str + requests method: GET, OPTIONS, HEAD, POST, PUT, + PATCH, or DELETE + url_path: Union[List[Union[str, int]], str, int] + URL components to make into a URL + payload: Optional[Mapping[str, Any]] + Data to send in the body of the Request. + params: Optional[Mapping[str, Any]] + Dictionary, list of tuples or bytes to send in the query + string for the Request. + **kwargs: Any + Additional arguments to send to the request method. + + Returns + ------- + Any + """ + url = APIConfig.make_url(url_path=url_path) + json_safe_payload = pydantic_core.to_jsonable_python(payload) + json_safe_params = pydantic_core.to_jsonable_python(params) + response = await self.arequest( + method=method, + url=url, + params=json_safe_params, + data=json_safe_payload, + **kwargs, + ) + data = self.process_response(response=response) + return data diff --git a/lunchable/models/assets.py b/lunchable/models/assets.py index 2ac81c26..2465d371 100644 --- a/lunchable/models/assets.py +++ b/lunchable/models/assets.py @@ -136,7 +136,7 @@ def get_assets(self) -> List[AssetsObject]: ------- List[AssetsObject] """ - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.GET, url_path=[APIConfig.LUNCHMONEY_ASSETS] ) assets = response_data.get(APIConfig.LUNCHMONEY_ASSETS) @@ -193,7 +193,7 @@ def update_asset( currency=currency, institution_name=institution_name, ).model_dump(exclude_none=True) - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.PUT, url_path=[APIConfig.LUNCHMONEY_ASSETS, asset_id], payload=payload, @@ -261,7 +261,7 @@ def insert_asset( closed_on=closed_on, exclude_transactions=exclude_transactions, ).model_dump(exclude_none=True) - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.POST, url_path=[APIConfig.LUNCHMONEY_ASSETS], payload=payload, diff --git a/lunchable/models/budgets.py b/lunchable/models/budgets.py index afbf527d..da78bb9b 100644 --- a/lunchable/models/budgets.py +++ b/lunchable/models/budgets.py @@ -139,7 +139,7 @@ def get_budgets( List[BudgetObject] """ params = BudgetParamsGet(start_date=start_date, end_date=end_date).model_dump() - response_data = self._make_request( + response_data = self.make_request( method="GET", url_path=[APIConfig.LUNCHMONEY_BUDGET], params=params ) budget_objects = [BudgetObject.model_validate(item) for item in response_data] @@ -190,7 +190,7 @@ def upsert_budget( amount=amount, currency=currency, ).model_dump(exclude_none=True) - response_data = self._make_request( + response_data = self.make_request( method="PUT", url_path=[APIConfig.LUNCHMONEY_BUDGET], payload=body ) @@ -215,7 +215,7 @@ def remove_budget(self, start_date: datetime.date, category_id: int) -> bool: params = BudgetParamsRemove( start_date=start_date, category_id=category_id ).model_dump() - response_data = self._make_request( + response_data = self.make_request( method="DELETE", url_path=[APIConfig.LUNCHMONEY_BUDGET], params=params ) return response_data diff --git a/lunchable/models/categories.py b/lunchable/models/categories.py index eab06116..cd4557ee 100644 --- a/lunchable/models/categories.py +++ b/lunchable/models/categories.py @@ -153,7 +153,7 @@ def get_categories(self) -> List[CategoriesObject]: ------- List[CategoriesObject] """ - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.GET, url_path=APIConfig.LUNCHMONEY_CATEGORIES ) categories = response_data["categories"] @@ -204,7 +204,7 @@ def insert_category( exclude_from_budget=exclude_from_budget, exclude_from_totals=exclude_from_totals, ).model_dump(exclude_none=True) - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.POST, url_path=APIConfig.LUNCHMONEY_CATEGORIES, payload=category_body, @@ -230,7 +230,7 @@ def get_category(self, category_id: int) -> CategoriesObject: ------- CategoriesObject """ - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.GET, url_path=[APIConfig.LUNCHMONEY_CATEGORIES, category_id], ) @@ -257,7 +257,7 @@ def remove_category(self, category_id: int) -> bool: ------- bool """ - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.DELETE, url_path=[APIConfig.LUNCHMONEY_CATEGORIES, category_id], ) @@ -291,7 +291,7 @@ def remove_category_force(self, category_id: int) -> bool: ------- bool """ - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.DELETE, url_path=[APIConfig.LUNCHMONEY_CATEGORIES, category_id, "force"], ) @@ -346,7 +346,7 @@ def update_category( exclude_from_totals=exclude_from_totals, group_id=group_id, ).model_dump(exclude_none=True) - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.PUT, url_path=[APIConfig.LUNCHMONEY_CATEGORIES, category_id], payload=payload, @@ -404,7 +404,7 @@ def insert_category_group( category_ids=category_ids, new_categories=new_categories, ).model_dump(exclude_none=True) - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.POST, url_path=[APIConfig.LUNCHMONEY_CATEGORIES, "group"], payload=payload, @@ -442,7 +442,7 @@ def insert_into_category_group( payload = _CategoriesAddParamsPost( category_ids=category_ids, new_categories=new_categories ).model_dump(exclude_none=True) - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.POST, url_path=[ APIConfig.LUNCHMONEY_CATEGORIES, diff --git a/lunchable/models/crypto.py b/lunchable/models/crypto.py index 6fe874e2..24562087 100644 --- a/lunchable/models/crypto.py +++ b/lunchable/models/crypto.py @@ -98,7 +98,7 @@ def get_crypto(self) -> List[CryptoObject]: ------- List[CryptoObject] """ - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.GET, url_path=APIConfig.LUNCHMONEY_CRYPTO ) crypto_data = response_data["crypto"] @@ -150,7 +150,7 @@ def update_crypto( balance=balance, currency=currency, ).model_dump(exclude_none=True) - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.PUT, url_path=[ APIConfig.LUNCHMONEY_CRYPTO, diff --git a/lunchable/models/plaid_accounts.py b/lunchable/models/plaid_accounts.py index 205b06f9..b185210c 100644 --- a/lunchable/models/plaid_accounts.py +++ b/lunchable/models/plaid_accounts.py @@ -116,7 +116,7 @@ def get_plaid_accounts(self) -> List[PlaidAccountObject]: ------- List[PlaidAccountObject] """ - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.GET, url_path=APIConfig.LUNCHMONEY_PLAID_ACCOUNTS ) accounts = response_data.get(APIConfig.LUNCHMONEY_PLAID_ACCOUNTS) diff --git a/lunchable/models/recurring_expenses.py b/lunchable/models/recurring_expenses.py index 212f9e22..cfaff58c 100644 --- a/lunchable/models/recurring_expenses.py +++ b/lunchable/models/recurring_expenses.py @@ -158,7 +158,7 @@ def get_recurring_expenses( params = RecurringExpenseParamsGet( start_date=start_date, debit_as_negative=debit_as_negative ).model_dump() - response_data = self._make_request( + response_data = self.make_request( method="GET", url_path=[APIConfig.LUNCH_MONEY_RECURRING_EXPENSES], params=params, diff --git a/lunchable/models/tags.py b/lunchable/models/tags.py index 26826116..22defdbb 100644 --- a/lunchable/models/tags.py +++ b/lunchable/models/tags.py @@ -48,7 +48,7 @@ def get_tags(self) -> List[TagsObject]: ------- List[TagsObject] """ - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.GET, url_path=APIConfig.LUNCHMONEY_TAGS ) tag_objects = [TagsObject.model_validate(item) for item in response_data] diff --git a/lunchable/models/transactions.py b/lunchable/models/transactions.py index 69e078b5..8cbc1642 100644 --- a/lunchable/models/transactions.py +++ b/lunchable/models/transactions.py @@ -537,7 +537,7 @@ def get_transactions( pending=pending, ).model_dump(exclude_none=True) search_params.update(params if params is not None else {}) - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.GET, url_path=APIConfig.LUNCHMONEY_TRANSACTIONS, params=search_params, @@ -573,7 +573,7 @@ def get_transaction(self, transaction_id: int) -> TransactionObject: The above code returns a :class:`.TransactionObject` with ID # 1234 (assuming it exists) """ - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.GET, url_path=[APIConfig.LUNCHMONEY_TRANSACTIONS, transaction_id], ) @@ -667,7 +667,7 @@ def update_transaction( if isinstance(transaction, TransactionObject): transaction = transaction.get_update_object() payload["transaction"] = transaction.model_dump(exclude_unset=True) - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.PUT, url_path=[APIConfig.LUNCHMONEY_TRANSACTIONS, transaction_id], payload=payload, @@ -752,7 +752,7 @@ def insert_transactions( debit_as_negative=debit_as_negative, skip_balance_update=skip_balance_update, ).model_dump(exclude_unset=True) - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.POST, url_path=APIConfig.LUNCHMONEY_TRANSACTIONS, payload=payload, @@ -805,7 +805,7 @@ def insert_transaction_group( tags=tags, transactions=transactions, ).model_dump(exclude_none=True) - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.POST, url_path=[ APIConfig.LUNCHMONEY_TRANSACTIONS, @@ -835,7 +835,7 @@ def remove_transaction_group(self, transaction_group_id: int) -> List[int]: ------- List[int] """ - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.DELETE, url_path=[ APIConfig.LUNCHMONEY_TRANSACTIONS, @@ -870,7 +870,7 @@ def unsplit_transactions( ------- List[int] """ - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.POST, url_path=[APIConfig.LUNCHMONEY_TRANSACTIONS, "unsplit"], payload=_TransactionsUnsplitPost( diff --git a/lunchable/models/user.py b/lunchable/models/user.py index ab22842e..6830368c 100644 --- a/lunchable/models/user.py +++ b/lunchable/models/user.py @@ -54,7 +54,7 @@ def get_user(self) -> UserObject: ------- UserObject """ - response_data = self._make_request( + response_data = self.make_request( method=self.Methods.GET, url_path=APIConfig.LUNCHMONEY_ME ) me = UserObject.model_validate(response_data) diff --git a/lunchable/plugins/pushlunch/pushover.py b/lunchable/plugins/pushlunch/pushover.py index e7276562..01fe75ac 100644 --- a/lunchable/plugins/pushlunch/pushover.py +++ b/lunchable/plugins/pushlunch/pushover.py @@ -10,7 +10,7 @@ from time import sleep from typing import Any, Dict, List, Optional -import requests +import httpx from lunchable.models import ( AssetsObject, @@ -60,7 +60,7 @@ def __init__( environment variable. """ super().__init__(access_token=lunchmoney_access_token) - self.pushover_session = requests.Session() + self.pushover_session = httpx.Client() self.pushover_session.headers.update({"Content-Type": "application/json"}) _courtesy_token = b"YXpwMzZ6MjExcWV5OGFvOXNicWF0cmdraXc4aGVz" @@ -91,7 +91,7 @@ def send_notification( sound: Optional[str] = None, timestamp: Optional[str] = None, html: bool = False, - ) -> requests.Response: + ) -> httpx.Response: """ Send a Pushover Notification @@ -126,7 +126,7 @@ def send_notification( Returns ------- - requests.Response + httpx.Response """ html_param = 1 if html not in [None, False] else None params_dict = { diff --git a/pyproject.toml b/pyproject.toml index 7c5d2dd0..828c3e0f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,8 +22,8 @@ classifiers = [ dependencies = [ "click>=8.0.1", "pydantic>=2,<3", - "requests>=2.0.0,<3.0.0", - "rich>=10.0.0" + "rich>=10.0.0", + "httpx" ] description = "A simple Python SDK around the Lunch Money Developer API" dynamic = ["version"] @@ -99,8 +99,8 @@ post-install-commands = [ type = "pip-compile" [tool.hatch.envs.default.scripts] -cov = "hatch run test:cov" -test = "hatch run test:test" +cov = "hatch run test:cov {args:}" +test = "hatch run test:test {args:}" [tool.hatch.envs.docs] dependencies = [ @@ -116,8 +116,6 @@ dependencies = [ "sphinx-autodoc-typehints", "autodoc_pydantic" ] -detached = true -type = "pip-compile" [tool.hatch.envs.docs.scripts] build = [ diff --git a/requirements.txt b/requirements.txt index eac24005..a078801f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,8 +2,8 @@ # This file is autogenerated by hatch-pip-compile with Python 3.11 # # - click>=8.0.1 +# - httpx # - pydantic<3,>=2 -# - requests<3.0.0,>=2.0.0 # - rich>=10.0.0 # - pandas # - python-dateutil @@ -12,14 +12,28 @@ annotated-types==0.6.0 # via pydantic +anyio==4.1.0 + # via httpx certifi==2023.11.17 - # via requests + # via + # httpcore + # httpx + # requests charset-normalizer==3.3.2 # via requests click==8.1.7 # via hatch.envs.default +h11==0.14.0 + # via httpcore +httpcore==1.0.2 + # via httpx +httpx==0.25.2 + # via hatch.envs.default idna==3.6 - # via requests + # via + # anyio + # httpx + # requests markdown-it-py==3.0.0 # via rich mdurl==0.1.2 @@ -44,7 +58,6 @@ pytz==2023.3.post1 # via pandas requests==2.31.0 # via - # hatch.envs.default # requests-oauthlib # splitwise requests-oauthlib==1.3.1 @@ -53,6 +66,10 @@ rich==13.7.0 # via hatch.envs.default six==1.16.0 # via python-dateutil +sniffio==1.3.0 + # via + # anyio + # httpx splitwise==2.5.0 # via hatch.envs.default typing-extensions==4.9.0 diff --git a/requirements/requirements-all.py3.10.txt b/requirements/requirements-all.py3.10.txt index 3335db20..b1bab5e1 100644 --- a/requirements/requirements-all.py3.10.txt +++ b/requirements/requirements-all.py3.10.txt @@ -6,8 +6,8 @@ # - pytest-mock # - vcrpy~=5.1.0 # - click>=8.0.1 +# - httpx # - pydantic<3,>=2 -# - requests<3.0.0,>=2.0.0 # - rich>=10.0.0 # - pandas # - python-dateutil @@ -16,8 +16,13 @@ annotated-types==0.6.0 # via pydantic +anyio==4.1.0 + # via httpx certifi==2023.11.17 - # via requests + # via + # httpcore + # httpx + # requests charset-normalizer==3.3.2 # via requests click==8.1.7 @@ -27,9 +32,19 @@ coverage==7.3.3 # hatch.envs.all.py3.10 # coverage exceptiongroup==1.2.0 - # via pytest + # via + # anyio + # pytest +h11==0.14.0 + # via httpcore +httpcore==1.0.2 + # via httpx +httpx==0.25.2 + # via hatch.envs.all.py3.10 idna==3.6 # via + # anyio + # httpx # requests # yarl iniconfig==2.0.0 @@ -72,7 +87,6 @@ pyyaml==6.0.1 # via vcrpy requests==2.31.0 # via - # hatch.envs.all.py3.10 # requests-oauthlib # splitwise requests-oauthlib==1.3.1 @@ -81,6 +95,10 @@ rich==13.7.0 # via hatch.envs.all.py3.10 six==1.16.0 # via python-dateutil +sniffio==1.3.0 + # via + # anyio + # httpx splitwise==2.5.0 # via hatch.envs.all.py3.10 tomli==2.0.1 diff --git a/requirements/requirements-all.py3.11.txt b/requirements/requirements-all.py3.11.txt index 6addace7..20c3e3a4 100644 --- a/requirements/requirements-all.py3.11.txt +++ b/requirements/requirements-all.py3.11.txt @@ -6,8 +6,8 @@ # - pytest-mock # - vcrpy~=5.1.0 # - click>=8.0.1 +# - httpx # - pydantic<3,>=2 -# - requests<3.0.0,>=2.0.0 # - rich>=10.0.0 # - pandas # - python-dateutil @@ -16,8 +16,13 @@ annotated-types==0.6.0 # via pydantic +anyio==4.1.0 + # via httpx certifi==2023.11.17 - # via requests + # via + # httpcore + # httpx + # requests charset-normalizer==3.3.2 # via requests click==8.1.7 @@ -26,8 +31,16 @@ coverage==7.3.3 # via # hatch.envs.all.py3.11 # coverage +h11==0.14.0 + # via httpcore +httpcore==1.0.2 + # via httpx +httpx==0.25.2 + # via hatch.envs.all.py3.11 idna==3.6 # via + # anyio + # httpx # requests # yarl iniconfig==2.0.0 @@ -70,7 +83,6 @@ pyyaml==6.0.1 # via vcrpy requests==2.31.0 # via - # hatch.envs.all.py3.11 # requests-oauthlib # splitwise requests-oauthlib==1.3.1 @@ -79,6 +91,10 @@ rich==13.7.0 # via hatch.envs.all.py3.11 six==1.16.0 # via python-dateutil +sniffio==1.3.0 + # via + # anyio + # httpx splitwise==2.5.0 # via hatch.envs.all.py3.11 typing-extensions==4.9.0 diff --git a/requirements/requirements-all.py3.12.txt b/requirements/requirements-all.py3.12.txt index 8301d5c0..0615d29b 100644 --- a/requirements/requirements-all.py3.12.txt +++ b/requirements/requirements-all.py3.12.txt @@ -6,8 +6,8 @@ # - pytest-mock # - vcrpy~=5.1.0 # - click>=8.0.1 +# - httpx # - pydantic<3,>=2 -# - requests<3.0.0,>=2.0.0 # - rich>=10.0.0 # - pandas # - python-dateutil @@ -16,8 +16,13 @@ annotated-types==0.6.0 # via pydantic +anyio==4.1.0 + # via httpx certifi==2023.11.17 - # via requests + # via + # httpcore + # httpx + # requests charset-normalizer==3.3.2 # via requests click==8.1.7 @@ -26,8 +31,16 @@ coverage==7.3.3 # via # hatch.envs.all.py3.12 # coverage +h11==0.14.0 + # via httpcore +httpcore==1.0.2 + # via httpx +httpx==0.25.2 + # via hatch.envs.all.py3.12 idna==3.6 # via + # anyio + # httpx # requests # yarl iniconfig==2.0.0 @@ -70,7 +83,6 @@ pyyaml==6.0.1 # via vcrpy requests==2.31.0 # via - # hatch.envs.all.py3.12 # requests-oauthlib # splitwise requests-oauthlib==1.3.1 @@ -79,6 +91,10 @@ rich==13.7.0 # via hatch.envs.all.py3.12 six==1.16.0 # via python-dateutil +sniffio==1.3.0 + # via + # anyio + # httpx splitwise==2.5.0 # via hatch.envs.all.py3.12 typing-extensions==4.9.0 diff --git a/requirements/requirements-all.py3.8.txt b/requirements/requirements-all.py3.8.txt index f434e858..fbc75680 100644 --- a/requirements/requirements-all.py3.8.txt +++ b/requirements/requirements-all.py3.8.txt @@ -6,8 +6,8 @@ # - pytest-mock # - vcrpy~=5.1.0 # - click>=8.0.1 +# - httpx # - pydantic<3,>=2 -# - requests<3.0.0,>=2.0.0 # - rich>=10.0.0 # - pandas # - python-dateutil @@ -16,8 +16,13 @@ annotated-types==0.6.0 # via pydantic +anyio==4.1.0 + # via httpx certifi==2023.11.17 - # via requests + # via + # httpcore + # httpx + # requests charset-normalizer==3.3.2 # via requests click==8.1.7 @@ -27,9 +32,19 @@ coverage==7.3.3 # hatch.envs.all.py3.8 # coverage exceptiongroup==1.2.0 - # via pytest + # via + # anyio + # pytest +h11==0.14.0 + # via httpcore +httpcore==1.0.2 + # via httpx +httpx==0.25.2 + # via hatch.envs.all.py3.8 idna==3.6 # via + # anyio + # httpx # requests # yarl iniconfig==2.0.0 @@ -72,7 +87,6 @@ pyyaml==6.0.1 # via vcrpy requests==2.31.0 # via - # hatch.envs.all.py3.8 # requests-oauthlib # splitwise requests-oauthlib==1.3.1 @@ -81,6 +95,10 @@ rich==13.7.0 # via hatch.envs.all.py3.8 six==1.16.0 # via python-dateutil +sniffio==1.3.0 + # via + # anyio + # httpx splitwise==2.5.0 # via hatch.envs.all.py3.8 tomli==2.0.1 diff --git a/requirements/requirements-all.py3.9.txt b/requirements/requirements-all.py3.9.txt index 9d6ba51e..c5cd0a37 100644 --- a/requirements/requirements-all.py3.9.txt +++ b/requirements/requirements-all.py3.9.txt @@ -6,8 +6,8 @@ # - pytest-mock # - vcrpy~=5.1.0 # - click>=8.0.1 +# - httpx # - pydantic<3,>=2 -# - requests<3.0.0,>=2.0.0 # - rich>=10.0.0 # - pandas # - python-dateutil @@ -16,8 +16,13 @@ annotated-types==0.6.0 # via pydantic +anyio==4.1.0 + # via httpx certifi==2023.11.17 - # via requests + # via + # httpcore + # httpx + # requests charset-normalizer==3.3.2 # via requests click==8.1.7 @@ -27,9 +32,19 @@ coverage==7.3.3 # hatch.envs.all.py3.9 # coverage exceptiongroup==1.2.0 - # via pytest + # via + # anyio + # pytest +h11==0.14.0 + # via httpcore +httpcore==1.0.2 + # via httpx +httpx==0.25.2 + # via hatch.envs.all.py3.9 idna==3.6 # via + # anyio + # httpx # requests # yarl iniconfig==2.0.0 @@ -72,7 +87,6 @@ pyyaml==6.0.1 # via vcrpy requests==2.31.0 # via - # hatch.envs.all.py3.9 # requests-oauthlib # splitwise requests-oauthlib==1.3.1 @@ -81,6 +95,10 @@ rich==13.7.0 # via hatch.envs.all.py3.9 six==1.16.0 # via python-dateutil +sniffio==1.3.0 + # via + # anyio + # httpx splitwise==2.5.0 # via hatch.envs.all.py3.9 tomli==2.0.1 diff --git a/requirements/requirements-docs.txt b/requirements/requirements-docs.txt index be4997da..ec9a4db9 100644 --- a/requirements/requirements-docs.txt +++ b/requirements/requirements-docs.txt @@ -1,6 +1,8 @@ # # This file is autogenerated by hatch-pip-compile with Python 3.11 # +# [constraints] requirements.txt (SHA256: 1d7f43c7c1ecbc074ece84ddfddf590007473fce44e813c9dca4481292391f67) +# # - sphinx # - sphinx-rtd-theme # - autodocsumm @@ -12,12 +14,25 @@ # - sphinx-click # - sphinx-autodoc-typehints # - autodoc_pydantic +# - click>=8.0.1 +# - httpx +# - pydantic<3,>=2 +# - rich>=10.0.0 +# - pandas +# - python-dateutil +# - splitwise<3.0.0,>=2.3.0 # alabaster==0.7.13 # via sphinx annotated-types==0.6.0 - # via pydantic + # via + # -c requirements.txt + # pydantic +anyio==4.1.0 + # via + # -c requirements.txt + # httpx autoclasstoc==1.6.0 # via hatch.envs.docs autodoc-pydantic==2.0.1 @@ -27,11 +42,20 @@ autodocsumm==0.2.11 babel==2.14.0 # via sphinx certifi==2023.11.17 - # via requests + # via + # -c requirements.txt + # httpcore + # httpx + # requests charset-normalizer==3.3.2 - # via requests + # via + # -c requirements.txt + # requests click==8.1.7 - # via sphinx-click + # via + # -c requirements.txt + # hatch.envs.docs + # sphinx-click docutils==0.20.1 # via # autoclasstoc @@ -39,8 +63,24 @@ docutils==0.20.1 # sphinx # sphinx-click # sphinx-rtd-theme +h11==0.14.0 + # via + # -c requirements.txt + # httpcore +httpcore==1.0.2 + # via + # -c requirements.txt + # httpx +httpx==0.25.2 + # via + # -c requirements.txt + # hatch.envs.docs idna==3.6 - # via requests + # via + # -c requirements.txt + # anyio + # httpx + # requests imagesize==1.4.1 # via sphinx jinja2==3.1.2 @@ -51,38 +91,91 @@ linkify-it-py==2.0.2 # via myst-parser 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 mdurl==0.1.2 - # via markdown-it-py + # via + # -c requirements.txt + # markdown-it-py more-itertools==10.1.0 # via autoclasstoc myst-parser==2.0.0 # via hatch.envs.docs +numpy==1.26.2 + # via + # -c requirements.txt + # pandas +oauthlib==3.2.2 + # via + # -c requirements.txt + # requests-oauthlib packaging==23.2 # via sphinx +pandas==2.1.4 + # via + # -c requirements.txt + # hatch.envs.docs pbr==6.0.0 # via sphinxcontrib-apidoc pydantic==2.5.2 # via + # -c requirements.txt + # hatch.envs.docs # autodoc-pydantic # pydantic-settings pydantic-core==2.14.5 - # via pydantic + # via + # -c requirements.txt + # pydantic pydantic-settings==2.1.0 # via autodoc-pydantic pygments==2.17.2 - # via sphinx + # via + # -c requirements.txt + # rich + # sphinx +python-dateutil==2.8.2 + # via + # -c requirements.txt + # hatch.envs.docs + # 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 requests==2.31.0 - # via sphinx + # via + # -c requirements.txt + # requests-oauthlib + # sphinx + # splitwise +requests-oauthlib==1.3.1 + # via + # -c requirements.txt + # splitwise +rich==13.7.0 + # via + # -c requirements.txt + # hatch.envs.docs +six==1.16.0 + # via + # -c requirements.txt + # python-dateutil +sniffio==1.3.0 + # via + # -c requirements.txt + # anyio + # httpx snowballstemmer==2.2.0 # via sphinx sphinx==7.2.6 @@ -130,11 +223,22 @@ sphinxcontrib-qthelp==1.0.6 # via sphinx sphinxcontrib-serializinghtml==1.1.9 # via sphinx +splitwise==2.5.0 + # via + # -c requirements.txt + # hatch.envs.docs typing-extensions==4.9.0 # via + # -c requirements.txt # 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 requests + # via + # -c requirements.txt + # requests diff --git a/requirements/requirements-lint.txt b/requirements/requirements-lint.txt index db26ff42..b37755ed 100644 --- a/requirements/requirements-lint.txt +++ b/requirements/requirements-lint.txt @@ -1,7 +1,7 @@ # # This file is autogenerated by hatch-pip-compile with Python 3.11 # -# [constraints] requirements.txt (SHA256: 2509b582e9eebc5409ade6b445d516a264326f540f095e367a11f5ac36ec6dce) +# [constraints] requirements.txt (SHA256: 1d7f43c7c1ecbc074ece84ddfddf590007473fce44e813c9dca4481292391f67) # # - mypy>=1.6.1 # - ruff~=0.1.7 diff --git a/requirements/requirements-test.txt b/requirements/requirements-test.txt index c6e75f21..3928cd95 100644 --- a/requirements/requirements-test.txt +++ b/requirements/requirements-test.txt @@ -1,15 +1,15 @@ # # This file is autogenerated by hatch-pip-compile with Python 3.11 # -# [constraints] requirements.txt (SHA256: 2509b582e9eebc5409ade6b445d516a264326f540f095e367a11f5ac36ec6dce) +# [constraints] requirements.txt (SHA256: 1d7f43c7c1ecbc074ece84ddfddf590007473fce44e813c9dca4481292391f67) # # - coverage[toml]>=6.5 # - pytest # - pytest-mock # - vcrpy~=5.1.0 # - click>=8.0.1 +# - httpx # - pydantic<3,>=2 -# - requests<3.0.0,>=2.0.0 # - rich>=10.0.0 # - pandas # - python-dateutil @@ -20,9 +20,15 @@ annotated-types==0.6.0 # via # -c requirements.txt # pydantic +anyio==4.1.0 + # via + # -c requirements.txt + # httpx certifi==2023.11.17 # via # -c requirements.txt + # httpcore + # httpx # requests charset-normalizer==3.3.2 # via @@ -36,9 +42,23 @@ coverage==7.3.3 # via # hatch.envs.test # coverage +h11==0.14.0 + # via + # -c requirements.txt + # httpcore +httpcore==1.0.2 + # via + # -c requirements.txt + # httpx +httpx==0.25.2 + # via + # -c requirements.txt + # hatch.envs.test idna==3.6 # via # -c requirements.txt + # anyio + # httpx # requests # yarl iniconfig==2.0.0 @@ -101,7 +121,6 @@ pyyaml==6.0.1 requests==2.31.0 # via # -c requirements.txt - # hatch.envs.test # requests-oauthlib # splitwise requests-oauthlib==1.3.1 @@ -116,6 +135,11 @@ six==1.16.0 # via # -c requirements.txt # python-dateutil +sniffio==1.3.0 + # via + # -c requirements.txt + # anyio + # httpx splitwise==2.5.0 # via # -c requirements.txt diff --git a/tests/conftest.py b/tests/conftest.py index b214c574..c665bf77 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -144,7 +144,6 @@ def path_transformer(path: str) -> str: vcr = VCR( filter_headers=(("authorization", "XXXXXXXXXX"),), filter_query_parameters=(("user", "XXXXXXXXXX"), ("token", "XXXXXXXXXX")), - decode_compressed_response=True, path_transformer=path_transformer, record_mode=os.getenv("VCR_RECORD_MODE", "once"), ) diff --git a/tests/models/cassettes/test_add_to_category_group.yaml b/tests/models/cassettes/test_add_to_category_group.yaml index 9dc94374..b14c026c 100644 --- a/tests/models/cassettes/test_add_to_category_group.yaml +++ b/tests/models/cassettes/test_add_to_category_group.yaml @@ -19,8 +19,7 @@ interactions: method: POST uri: https://dev.lunchmoney.app/v1/categories/group/658694/add response: - body: - string: '{"id":658694,"name":"Test Category Group","description":"Test Category Group!!","is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"is_group":true,"group_id":null,"children":[{"id":658761,"name":"Another Another Test Category","description":null,"created_at":"2023-12-15T02:42:01.147Z","archived":false,"archived_on":null},{"id":443128,"name":"Groceries","description":"Test Category Description Updated","created_at":"2023-03-07T02:10:27.268Z","archived":false,"archived_on":null}],"archived":false,"archived_on":null}' + content: '{"id":658694,"name":"Test Category Group","description":"Test Category Group!!","is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"is_group":true,"group_id":null,"children":[{"id":658761,"name":"Another Another Test Category","description":null,"created_at":"2023-12-15T02:42:01.147Z","archived":false,"archived_on":null},{"id":443128,"name":"Groceries","description":"Test Category Description Updated","created_at":"2023-03-07T02:10:27.268Z","archived":false,"archived_on":null}],"archived":false,"archived_on":null}' headers: Access-Control-Allow-Credentials: - 'true' @@ -48,7 +47,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_create_and_delete_transaction_group.yaml b/tests/models/cassettes/test_create_and_delete_transaction_group.yaml index f28fbc00..ad316382 100644 --- a/tests/models/cassettes/test_create_and_delete_transaction_group.yaml +++ b/tests/models/cassettes/test_create_and_delete_transaction_group.yaml @@ -19,8 +19,7 @@ interactions: method: POST uri: https://dev.lunchmoney.app/v1/transactions/group response: - body: - string: '561178199' + content: '561178199' headers: Access-Control-Allow-Credentials: - 'true' @@ -48,9 +47,8 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 - request: body: headers: @@ -71,8 +69,7 @@ interactions: method: DELETE uri: https://dev.lunchmoney.app/v1/transactions/group/561178199 response: - body: - string: '{"transactions":[546452296,546434806]}' + content: '{"transactions":[546452296,546434806]}' headers: Access-Control-Allow-Credentials: - 'true' @@ -100,7 +97,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_create_asset.yaml b/tests/models/cassettes/test_create_asset.yaml index 84f4c633..7901d1d3 100644 --- a/tests/models/cassettes/test_create_asset.yaml +++ b/tests/models/cassettes/test_create_asset.yaml @@ -19,8 +19,7 @@ interactions: method: POST uri: https://dev.lunchmoney.app/v1/assets response: - body: - string: '{"id":78214,"type_name":"depository","subtype_name":null,"name":"test-account-1","display_name":"Test Account #1","balance":"4.2000","balance_as_of":"2023-12-15T02:24:12.156Z","closed_on":null,"created_at":"2023-12-15T02:24:12.158Z","currency":"usd","institution_name":"Test Institution","exclude_transactions":false}' + content: '{"id":78214,"type_name":"depository","subtype_name":null,"name":"test-account-1","display_name":"Test Account #1","balance":"4.2000","balance_as_of":"2023-12-15T02:24:12.156Z","closed_on":null,"created_at":"2023-12-15T02:24:12.158Z","currency":"usd","institution_name":"Test Institution","exclude_transactions":false}' headers: Access-Control-Allow-Credentials: - 'true' @@ -48,7 +47,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_create_category.yaml b/tests/models/cassettes/test_create_category.yaml index 9895ca8f..bd2ff9f0 100644 --- a/tests/models/cassettes/test_create_category.yaml +++ b/tests/models/cassettes/test_create_category.yaml @@ -19,8 +19,7 @@ interactions: method: POST uri: https://dev.lunchmoney.app/v1/categories response: - body: - string: '{"category_id":658693}' + content: '{"category_id":658693}' headers: Access-Control-Allow-Credentials: - 'true' @@ -48,7 +47,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_create_category_group.yaml b/tests/models/cassettes/test_create_category_group.yaml index b6e53cb4..456b4ed1 100644 --- a/tests/models/cassettes/test_create_category_group.yaml +++ b/tests/models/cassettes/test_create_category_group.yaml @@ -19,8 +19,7 @@ interactions: method: POST uri: https://dev.lunchmoney.app/v1/categories/group response: - body: - string: '{"category_id":658694}' + content: '{"category_id":658694}' headers: Access-Control-Allow-Credentials: - 'true' @@ -48,7 +47,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_delete_budget.yaml b/tests/models/cassettes/test_delete_budget.yaml index 75128167..0aedf80c 100644 --- a/tests/models/cassettes/test_delete_budget.yaml +++ b/tests/models/cassettes/test_delete_budget.yaml @@ -19,8 +19,7 @@ interactions: method: DELETE uri: https://dev.lunchmoney.app/v1/budgets?category_id=443127&start_date=2022-11-01 response: - body: - string: 'true' + content: 'true' headers: Access-Control-Allow-Credentials: - 'true' @@ -48,7 +47,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_delete_category.yaml b/tests/models/cassettes/test_delete_category.yaml index 55474bb1..a85f4d60 100644 --- a/tests/models/cassettes/test_delete_category.yaml +++ b/tests/models/cassettes/test_delete_category.yaml @@ -19,8 +19,7 @@ interactions: method: DELETE uri: https://dev.lunchmoney.app/v1/categories/343088 response: - body: - string: 'true' + content: 'true' headers: Access-Control-Allow-Credentials: - 'true' @@ -48,7 +47,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_delete_category_force.yaml b/tests/models/cassettes/test_delete_category_force.yaml index 3773dc2c..dffbbb7e 100644 --- a/tests/models/cassettes/test_delete_category_force.yaml +++ b/tests/models/cassettes/test_delete_category_force.yaml @@ -19,8 +19,7 @@ interactions: method: DELETE uri: https://dev.lunchmoney.app/v1/categories/343089/force response: - body: - string: 'true' + content: 'true' headers: Access-Control-Allow-Credentials: - 'true' @@ -48,7 +47,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_get_assets.yaml b/tests/models/cassettes/test_get_assets.yaml index 822435bb..c2977143 100644 --- a/tests/models/cassettes/test_get_assets.yaml +++ b/tests/models/cassettes/test_get_assets.yaml @@ -17,8 +17,7 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/assets response: - body: - string: '{"assets":[{"id":49335,"type_name":"cash","subtype_name":"checking","name":"Test Account","display_name":null,"balance":"-16513.5500","balance_as_of":"2023-03-07T02:43:48.383Z","closed_on":null,"currency":"usd","institution_name":null,"exclude_transactions":false,"created_at":"2023-03-07T02:05:23.670Z"}]}' + content: '{"assets":[{"id":49335,"type_name":"cash","subtype_name":"checking","name":"Test Account","display_name":null,"balance":"-16513.5500","balance_as_of":"2023-03-07T02:43:48.383Z","closed_on":null,"currency":"usd","institution_name":null,"exclude_transactions":false,"created_at":"2023-03-07T02:05:23.670Z"}]}' headers: Access-Control-Allow-Credentials: - 'true' @@ -46,7 +45,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_get_budgets.yaml b/tests/models/cassettes/test_get_budgets.yaml index 21536a2c..8877774c 100644 --- a/tests/models/cassettes/test_get_budgets.yaml +++ b/tests/models/cassettes/test_get_budgets.yaml @@ -17,8 +17,7 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/budgets?end_date=2022-11-29&start_date=2022-11-01 response: - body: - string: '[{"category_name":"Uncategorized","category_id":null,"is_group":false,"group_id":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"archived":false,"data":{"2022-11-01":{}},"config":null,"order":0},{"category_name":"Uncategorized","category_id":null,"is_group":false,"group_id":null,"is_income":true,"exclude_from_budget":false,"exclude_from_totals":false,"archived":false,"data":{"2022-11-01":{}},"config":null,"order":1},{"category_name":"Groceries","category_id":443128,"category_group_name":null,"group_id":null,"is_group":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"order":2,"archived":false,"data":{"2022-11-01":{"num_transactions":1,"spending_to_base":28.15}},"config":null},{"category_name":"Home","category_id":443125,"category_group_name":null,"group_id":null,"is_group":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"order":3,"archived":false,"data":{"2022-11-01":{"num_transactions":0,"spending_to_base":0}},"config":null},{"category_name":"Income","category_id":443129,"category_group_name":null,"group_id":null,"is_group":null,"is_income":true,"exclude_from_budget":false,"exclude_from_totals":false,"order":4,"archived":false,"data":{"2022-11-01":{"num_transactions":0,"spending_to_base":0}},"config":null},{"category_name":"Personal Care","category_id":443127,"category_group_name":null,"group_id":null,"is_group":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"order":5,"archived":false,"data":{"2022-11-01":{"num_transactions":0,"spending_to_base":0}},"config":null},{"category_name":"Shopping","category_id":443126,"category_group_name":null,"group_id":null,"is_group":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"order":6,"archived":false,"data":{"2022-11-01":{"num_transactions":10,"spending_to_base":711.69}},"config":null}]' + content: '[{"category_name":"Uncategorized","category_id":null,"is_group":false,"group_id":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"archived":false,"data":{"2022-11-01":{}},"config":null,"order":0},{"category_name":"Uncategorized","category_id":null,"is_group":false,"group_id":null,"is_income":true,"exclude_from_budget":false,"exclude_from_totals":false,"archived":false,"data":{"2022-11-01":{}},"config":null,"order":1},{"category_name":"Groceries","category_id":443128,"category_group_name":null,"group_id":null,"is_group":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"order":2,"archived":false,"data":{"2022-11-01":{"num_transactions":1,"spending_to_base":28.15}},"config":null},{"category_name":"Home","category_id":443125,"category_group_name":null,"group_id":null,"is_group":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"order":3,"archived":false,"data":{"2022-11-01":{"num_transactions":0,"spending_to_base":0}},"config":null},{"category_name":"Income","category_id":443129,"category_group_name":null,"group_id":null,"is_group":null,"is_income":true,"exclude_from_budget":false,"exclude_from_totals":false,"order":4,"archived":false,"data":{"2022-11-01":{"num_transactions":0,"spending_to_base":0}},"config":null},{"category_name":"Personal Care","category_id":443127,"category_group_name":null,"group_id":null,"is_group":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"order":5,"archived":false,"data":{"2022-11-01":{"num_transactions":0,"spending_to_base":0}},"config":null},{"category_name":"Shopping","category_id":443126,"category_group_name":null,"group_id":null,"is_group":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"order":6,"archived":false,"data":{"2022-11-01":{"num_transactions":10,"spending_to_base":711.69}},"config":null}]' headers: Access-Control-Allow-Credentials: - 'true' @@ -48,7 +47,6 @@ interactions: - Express content-length: - '1911' - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_get_categories.yaml b/tests/models/cassettes/test_get_categories.yaml index 55a77f8c..ee4ce41e 100644 --- a/tests/models/cassettes/test_get_categories.yaml +++ b/tests/models/cassettes/test_get_categories.yaml @@ -17,8 +17,7 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/categories response: - body: - string: '{"categories":[{"id":443128,"name":"Groceries","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:27.268Z","created_at":"2023-03-07T02:10:27.268Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443125,"name":"Home","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:09:42.960Z","created_at":"2023-03-07T02:09:42.960Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443129,"name":"Income","description":null,"is_income":true,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:40:15.216Z","created_at":"2023-03-07T02:40:15.216Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443127,"name":"Personal Care","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:17.225Z","created_at":"2023-03-07T02:10:17.225Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443126,"name":"Shopping","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:12.260Z","created_at":"2023-03-07T02:10:12.260Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null}]}' + content: '{"categories":[{"id":443128,"name":"Groceries","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:27.268Z","created_at":"2023-03-07T02:10:27.268Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443125,"name":"Home","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:09:42.960Z","created_at":"2023-03-07T02:09:42.960Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443129,"name":"Income","description":null,"is_income":true,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:40:15.216Z","created_at":"2023-03-07T02:40:15.216Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443127,"name":"Personal Care","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:17.225Z","created_at":"2023-03-07T02:10:17.225Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443126,"name":"Shopping","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:12.260Z","created_at":"2023-03-07T02:10:12.260Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null}]}' headers: Access-Control-Allow-Credentials: - 'true' @@ -48,7 +47,6 @@ interactions: - Express content-length: - '1450' - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_get_category.yaml b/tests/models/cassettes/test_get_category.yaml index f7cb43be..1caa2f7f 100644 --- a/tests/models/cassettes/test_get_category.yaml +++ b/tests/models/cassettes/test_get_category.yaml @@ -17,8 +17,7 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/categories/443128 response: - body: - string: '{"id":443128,"name":"Groceries","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null}' + content: '{"id":443128,"name":"Groceries","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null}' headers: Access-Control-Allow-Credentials: - 'true' @@ -46,7 +45,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_get_crypto.yaml b/tests/models/cassettes/test_get_crypto.yaml index 84c982b8..df3509bd 100644 --- a/tests/models/cassettes/test_get_crypto.yaml +++ b/tests/models/cassettes/test_get_crypto.yaml @@ -17,8 +17,7 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/crypto response: - body: - string: '{"crypto":[{"id":7286,"source":"manual","created_at":"2023-12-15T03:02:18.331Z","name":"Bitcoin","display_name":null,"balance":"1.000000000000000000","balance_as_of":"2023-12-15T03:00:08.292Z","currency":"BTC","status":"active","institution_name":null}]}' + content: '{"crypto":[{"id":7286,"source":"manual","created_at":"2023-12-15T03:02:18.331Z","name":"Bitcoin","display_name":null,"balance":"1.000000000000000000","balance_as_of":"2023-12-15T03:00:08.292Z","currency":"BTC","status":"active","institution_name":null}]}' headers: Access-Control-Allow-Credentials: - 'true' @@ -46,7 +45,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_get_plaid_accounts.yaml b/tests/models/cassettes/test_get_plaid_accounts.yaml index 2566ea6d..7a51a818 100644 --- a/tests/models/cassettes/test_get_plaid_accounts.yaml +++ b/tests/models/cassettes/test_get_plaid_accounts.yaml @@ -17,50 +17,7 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/plaid_accounts response: - body: - string: | - { - "plaid_accounts": [ - { - "id": 71394, - "date_linked": "2023-12-15", - "name": "Chase - Freedom", - "display_name": "Chase Freedom", - "type": "credit", - "subtype": "creditcard", - "mask": "5678", - "institution_name": "Chase", - "status": "active", - "limit": 12345, - "balance": "123.0900", - "currency": "usd", - "balance_last_update": "2023-12-14T15:55:00.753Z", - "import_start_date": "2023-02-06", - "last_import": "2023-12-14T15:55:03.163Z", - "last_fetch": "2023-12-14T15:55:03.301Z", - "plaid_last_successful_update": "2023-12-13T15:51:37.490Z" - }, - { - "id": 71395, - "date_linked": "2023-12-15", - "name": "Chase - Sapphire", - "display_name": "Chase Sapphire", - "type": "credit", - "subtype": "creditcard", - "mask": "1234", - "institution_name": "Chase", - "status": "active", - "limit": 12345, - "balance": "456.0900", - "currency": "usd", - "balance_last_update": "2023-12-14T15:55:00.753Z", - "import_start_date": "2023-02-06", - "last_import": "2023-12-14T15:55:03.163Z", - "last_fetch": "2023-12-14T15:55:03.301Z", - "plaid_last_successful_update": "2023-12-13T15:51:37.490Z" - } - ] - } + content: '{"plaid_accounts": [{"id": 71394, "date_linked": "2023-12-15", "name": "Chase - Freedom", "display_name": "Chase Freedom", "type": "credit", "subtype": "creditcard", "mask": "5678", "institution_name": "Chase", "status": "active", "limit": 12345, "balance": "123.0900", "currency": "usd", "balance_last_update": "2023-12-14T15:55:00.753Z", "import_start_date": "2023-02-06", "last_import": "2023-12-14T15:55:03.163Z", "last_fetch": "2023-12-14T15:55:03.301Z", "plaid_last_successful_update": "2023-12-13T15:51:37.490Z"}, {"id": 71395, "date_linked": "2023-12-15", "name": "Chase - Sapphire", "display_name": "Chase Sapphire", "type": "credit", "subtype": "creditcard", "mask": "1234", "institution_name": "Chase", "status": "active", "limit": 12345, "balance": "456.0900", "currency": "usd", "balance_last_update": "2023-12-14T15:55:00.753Z", "import_start_date": "2023-02-06", "last_import": "2023-12-14T15:55:03.163Z", "last_fetch": "2023-12-14T15:55:03.301Z", "plaid_last_successful_update": "2023-12-13T15:51:37.490Z"}]}' headers: Access-Control-Allow-Credentials: - 'true' @@ -90,7 +47,6 @@ interactions: - Express content-length: - '8024' - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_get_recurring_expenses.yaml b/tests/models/cassettes/test_get_recurring_expenses.yaml index 85bf913b..0dad9f3a 100644 --- a/tests/models/cassettes/test_get_recurring_expenses.yaml +++ b/tests/models/cassettes/test_get_recurring_expenses.yaml @@ -15,10 +15,9 @@ interactions: authorization: - XXXXXXXXXX method: GET - uri: https://dev.lunchmoney.app/v1/recurring_expenses?debit_as_negative=False&start_date=2022-11-01 + uri: https://dev.lunchmoney.app/v1/recurring_expenses?debit_as_negative=false&start_date=2022-11-01 response: - body: - string: '{"recurring_expenses":[{"id":585244,"start_date":"2021-12-01","end_date":null,"cadence":"monthly","payee":"Test Item","amount":"100.0000","currency":"usd","created_at":"2023-12-15T02:38:04.131Z","description":"Video Streaming","billing_date":"2022-11-01","type":"cleared","original_name":null,"source":"manual","plaid_account_id":null,"asset_id":null,"category_id":443126,"transaction_id":null}]}' + content: '{"recurring_expenses":[{"id":585244,"start_date":"2021-12-01","end_date":null,"cadence":"monthly","payee":"Test Item","amount":"100.0000","currency":"usd","created_at":"2023-12-15T02:38:04.131Z","description":"Video Streaming","billing_date":"2022-11-01","type":"cleared","original_name":null,"source":"manual","plaid_account_id":null,"asset_id":null,"category_id":443126,"transaction_id":null}]}' headers: Access-Control-Allow-Credentials: - 'true' @@ -46,7 +45,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_get_tags.yaml b/tests/models/cassettes/test_get_tags.yaml index 34e41128..c3b5c84f 100644 --- a/tests/models/cassettes/test_get_tags.yaml +++ b/tests/models/cassettes/test_get_tags.yaml @@ -17,8 +17,7 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/tags response: - body: - string: '[{"id":66845,"name":"test","description":null,"archived":false}]' + content: '[{"id":66845,"name":"test","description":null,"archived":false}]' headers: Access-Control-Allow-Credentials: - 'true' @@ -46,7 +45,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_get_transaction.yaml b/tests/models/cassettes/test_get_transaction.yaml index 27411ad0..2bac6126 100644 --- a/tests/models/cassettes/test_get_transaction.yaml +++ b/tests/models/cassettes/test_get_transaction.yaml @@ -17,8 +17,7 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/transactions/546434806 response: - body: - string: '{"id":546434806,"date":"2023-12-12","payee":"Example Restaurant","amount":"120.0000","currency":"usd","to_base":120,"notes":"Saturday Dinner","category_id":null,"recurring_id":null,"asset_id":null,"plaid_account_id":null,"status":"uncleared","is_group":false,"group_id":null,"parent_id":null,"has_children":null,"tags":[],"external_id":null,"original_name":"Example Restaurant","type":null,"subtype":null}' + content: '{"id":546434806,"date":"2023-12-12","payee":"Example Restaurant","amount":"120.0000","currency":"usd","to_base":120,"notes":"Saturday Dinner","category_id":null,"recurring_id":null,"asset_id":null,"plaid_account_id":null,"status":"uncleared","is_group":false,"group_id":null,"parent_id":null,"has_children":null,"tags":[],"external_id":null,"original_name":"Example Restaurant","type":null,"subtype":null}' headers: Access-Control-Allow-Credentials: - 'true' @@ -46,7 +45,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_get_transactions.yaml b/tests/models/cassettes/test_get_transactions.yaml index 47219fc1..3c8c0feb 100644 --- a/tests/models/cassettes/test_get_transactions.yaml +++ b/tests/models/cassettes/test_get_transactions.yaml @@ -17,8 +17,7 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/transactions response: - body: - string: '{"transactions":[{"id":546434806,"date":"2023-12-12","original_date":null,"payee":"Example Restaurant","amount":"120.0000","currency":"usd","to_base":120,"notes":"Saturday Dinner","category_id":null,"recurring_id":null,"asset_id":null,"plaid_account_id":null,"status":"uncleared","is_group":false,"group_id":null,"parent_id":null,"tags":[],"external_id":null,"original_name":"Example Restaurant","type":null,"subtype":null},{"id":546452296,"date":"2023-12-12","original_date":null,"payee":"Example Restaurant","amount":"120.0000","currency":"usd","to_base":120,"notes":"Saturday Dinner","category_id":null,"recurring_id":null,"asset_id":null,"plaid_account_id":null,"status":"uncleared","is_group":false,"group_id":null,"parent_id":null,"tags":[],"external_id":"1234","original_name":"Example Restaurant","type":null,"subtype":null}]}' + content: '{"transactions":[{"id":546434806,"date":"2023-12-12","original_date":null,"payee":"Example Restaurant","amount":"120.0000","currency":"usd","to_base":120,"notes":"Saturday Dinner","category_id":null,"recurring_id":null,"asset_id":null,"plaid_account_id":null,"status":"uncleared","is_group":false,"group_id":null,"parent_id":null,"tags":[],"external_id":null,"original_name":"Example Restaurant","type":null,"subtype":null},{"id":546452296,"date":"2023-12-12","original_date":null,"payee":"Example Restaurant","amount":"120.0000","currency":"usd","to_base":120,"notes":"Saturday Dinner","category_id":null,"recurring_id":null,"asset_id":null,"plaid_account_id":null,"status":"uncleared","is_group":false,"group_id":null,"parent_id":null,"tags":[],"external_id":"1234","original_name":"Example Restaurant","type":null,"subtype":null}]}' headers: Access-Control-Allow-Credentials: - 'true' @@ -46,7 +45,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_get_uncleared_transactions.yaml b/tests/models/cassettes/test_get_uncleared_transactions.yaml new file mode 100644 index 00000000..e39061a1 --- /dev/null +++ b/tests/models/cassettes/test_get_uncleared_transactions.yaml @@ -0,0 +1,54 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + authorization: + - XXXXXXXXXX + connection: + - keep-alive + content-type: + - application/json + host: + - dev.lunchmoney.app + user-agent: + - lunchable/0.10.0 + method: GET + uri: https://dev.lunchmoney.app/v1/transactions?status=uncleared + response: + content: '{"transactions":[{"id":546452296,"date":"2023-12-12","original_date":null,"payee":"Example Restaurant","amount":"120.0000","currency":"usd","to_base":120,"notes":"Updated on 2023-12-14 20:10:09.718861","category_id":658693,"recurring_id":null,"asset_id":null,"plaid_account_id":null,"status":"uncleared","is_group":false,"group_id":null,"parent_id":null,"has_children":null,"tags":[],"external_id":"1234","original_name":"Example Restaurant","type":null,"subtype":null},{"id":561279455,"date":"2023-12-12","original_date":null,"payee":"Example Restaurant","amount":"60.0000","currency":"usd","to_base":60,"notes":"Saturday Dinner","category_id":443126,"recurring_id":null,"asset_id":null,"plaid_account_id":null,"status":"uncleared","is_group":false,"group_id":null,"parent_id":546434806,"has_children":null,"tags":[],"external_id":null,"original_name":null,"type":null,"subtype":null},{"id":561279456,"date":"2023-12-12","original_date":null,"payee":"Example Restaurant","amount":"60.0000","currency":"usd","to_base":60,"notes":"Saturday Dinner","category_id":443127,"recurring_id":null,"asset_id":null,"plaid_account_id":null,"status":"uncleared","is_group":false,"group_id":null,"parent_id":546434806,"has_children":null,"tags":[],"external_id":null,"original_name":null,"type":null,"subtype":null},{"id":561205301,"date":"2023-12-14","original_date":null,"payee":"Random Test","amount":"3.5000","currency":"usd","to_base":3.5,"notes":"Random Test Description: 2023-12-14 20:01:42.588685","category_id":443129,"recurring_id":null,"asset_id":49335,"plaid_account_id":null,"status":"uncleared","is_group":false,"group_id":null,"parent_id":null,"has_children":null,"tags":[],"external_id":null,"original_name":"Random Test","type":null,"subtype":null}]}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json; charset=utf-8 + Date: + - Sat, 16 Dec 2023 04:58:01 GMT + Etag: + - W/"6d9-Hbzau0mQltfn4+9X1e5HlY8T0Jw" + Nel: + - '{"report_to":"heroku-nel","max_age":3600,"success_fraction":0.005,"failure_fraction":0.05,"response_headers":["Via"]}' + Report-To: + - '{"group":"heroku-nel","max_age":3600,"endpoints":[{"url":"https://nel.heroku.com/reports?ts=1702702680&sid=1b10b0ff-8a76-4548-befa-353fc6c6c045&s=U8zDcQAjevLxTY7sXga%2BxHDelU1ZdTXuO6MMsBzCYxs%3D"}]}' + Reporting-Endpoints: + - heroku-nel=https://nel.heroku.com/reports?ts=1702702680&sid=1b10b0ff-8a76-4548-befa-353fc6c6c045&s=U8zDcQAjevLxTY7sXga%2BxHDelU1ZdTXuO6MMsBzCYxs%3D + Server: + - Cowboy + Transfer-Encoding: + - chunked + Vary: + - Origin, Accept-Encoding + Via: + - 1.1 vegur + X-Powered-By: + - Express + http_version: HTTP/1.1 + status_code: 200 +version: 1 diff --git a/tests/models/cassettes/test_get_user.yaml b/tests/models/cassettes/test_get_user.yaml index 7987290e..dbf5b5db 100644 --- a/tests/models/cassettes/test_get_user.yaml +++ b/tests/models/cassettes/test_get_user.yaml @@ -17,8 +17,7 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/me response: - body: - string: '{"user_name":"Justin Flannery","user_email":"juftin@gmail.com","user_id":12126,"account_id":18286,"budget_name":"🤖 Juftin - Sandbox","api_key_label":"Lunchable"}' + content: '{"user_name":"Justin Flannery","user_email":"juftin@gmail.com","user_id":12126,"account_id":18286,"budget_name":"🤖 Juftin - Sandbox","api_key_label":"Lunchable"}' headers: Access-Control-Allow-Credentials: - 'true' @@ -46,7 +45,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_insert_transactions.yaml b/tests/models/cassettes/test_insert_transactions.yaml index 9c30af2c..3aecbd47 100644 --- a/tests/models/cassettes/test_insert_transactions.yaml +++ b/tests/models/cassettes/test_insert_transactions.yaml @@ -19,8 +19,7 @@ interactions: method: POST uri: https://dev.lunchmoney.app/v1/transactions response: - body: - string: '{"ids":[561205301]}' + content: '{"ids":[561205301]}' headers: Access-Control-Allow-Credentials: - 'true' @@ -48,7 +47,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_split_transaction.yaml b/tests/models/cassettes/test_split_transaction.yaml index 7c3272aa..68cb7dbb 100644 --- a/tests/models/cassettes/test_split_transaction.yaml +++ b/tests/models/cassettes/test_split_transaction.yaml @@ -17,8 +17,7 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/transactions/546434806 response: - body: - string: '{"id":546434806,"date":"2023-12-12","payee":"Example Restaurant","amount":"120.0000","currency":"usd","to_base":120,"notes":"Saturday Dinner","category_id":null,"recurring_id":null,"asset_id":null,"plaid_account_id":null,"status":"uncleared","is_group":false,"group_id":null,"parent_id":null,"has_children":null,"tags":[],"external_id":null,"original_name":"Example Restaurant","type":null,"subtype":null}' + content: '{"id":546434806,"date":"2023-12-12","payee":"Example Restaurant","amount":"120.0000","currency":"usd","to_base":120,"notes":"Saturday Dinner","category_id":null,"recurring_id":null,"asset_id":null,"plaid_account_id":null,"status":"uncleared","is_group":false,"group_id":null,"parent_id":null,"has_children":null,"tags":[],"external_id":null,"original_name":"Example Restaurant","type":null,"subtype":null}' headers: Access-Control-Allow-Credentials: - 'true' @@ -46,9 +45,8 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 - request: body: '{"split": [{"date": "2023-12-12", "notes": "Saturday Dinner", "amount": 60.0}, {"date": "2023-12-12", "notes": "Saturday Dinner", "amount": 60.0}], "debit_as_negative": false, "skip_balance_update": true}' headers: @@ -69,8 +67,7 @@ interactions: method: PUT uri: https://dev.lunchmoney.app/v1/transactions/546434806 response: - body: - string: '{"updated":true,"split":[561279455,561279456]}' + content: '{"updated":true,"split":[561279455,561279456]}' headers: Access-Control-Allow-Credentials: - 'true' @@ -98,7 +95,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_unsplit_transaction.yaml b/tests/models/cassettes/test_unsplit_transaction.yaml index 4adcb511..6704d8b0 100644 --- a/tests/models/cassettes/test_unsplit_transaction.yaml +++ b/tests/models/cassettes/test_unsplit_transaction.yaml @@ -19,8 +19,7 @@ interactions: method: POST uri: https://dev.lunchmoney.app/v1/transactions/unsplit response: - body: - string: '[103958755,103958756,103958497]' + content: '[103958755,103958756,103958497]' headers: Access-Control-Allow-Credentials: - 'true' @@ -42,7 +41,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_update_asset.yaml b/tests/models/cassettes/test_update_asset.yaml index 7a49eee6..0d8be0fa 100644 --- a/tests/models/cassettes/test_update_asset.yaml +++ b/tests/models/cassettes/test_update_asset.yaml @@ -19,8 +19,7 @@ interactions: method: PUT uri: https://dev.lunchmoney.app/v1/assets/78214 response: - body: - string: '{"id":78214,"type_name":"cash","subtype_name":null,"name":"test-account-1","display_name":"Test Account #1","balance":"5.2000","balance_as_of":"2023-12-15T02:26:08.599Z","closed_on":null,"currency":"usd","institution_name":"Test Institution","exclude_transactions":false,"created_at":"2023-12-15T02:24:12.158Z"}' + content: '{"id":78214,"type_name":"cash","subtype_name":null,"name":"test-account-1","display_name":"Test Account #1","balance":"5.2000","balance_as_of":"2023-12-15T02:26:08.599Z","closed_on":null,"currency":"usd","institution_name":"Test Institution","exclude_transactions":false,"created_at":"2023-12-15T02:24:12.158Z"}' headers: Access-Control-Allow-Credentials: - 'true' @@ -48,7 +47,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_update_category.yaml b/tests/models/cassettes/test_update_category.yaml index 64d88b63..31475522 100644 --- a/tests/models/cassettes/test_update_category.yaml +++ b/tests/models/cassettes/test_update_category.yaml @@ -19,8 +19,7 @@ interactions: method: PUT uri: https://dev.lunchmoney.app/v1/categories/443128 response: - body: - string: 'true' + content: 'true' headers: Access-Control-Allow-Credentials: - 'true' @@ -48,7 +47,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_update_crypto.yaml b/tests/models/cassettes/test_update_crypto.yaml index 80da5dc7..b67480f2 100644 --- a/tests/models/cassettes/test_update_crypto.yaml +++ b/tests/models/cassettes/test_update_crypto.yaml @@ -19,8 +19,7 @@ interactions: method: PUT uri: https://dev.lunchmoney.app/v1/crypto/manual/7286 response: - body: - string: '{"id":7286,"source":"manual","created_at":"2023-12-15T03:02:18.331Z","name":"Bitcoin","display_name":null,"balance":"0.500000000000000000","institution_name":null}' + content: '{"id":7286,"source":"manual","created_at":"2023-12-15T03:02:18.331Z","name":"Bitcoin","display_name":null,"balance":"0.500000000000000000","institution_name":null}' headers: Access-Control-Allow-Credentials: - 'true' @@ -48,7 +47,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_update_transaction.yaml b/tests/models/cassettes/test_update_transaction.yaml index fb91f45d..97defa43 100644 --- a/tests/models/cassettes/test_update_transaction.yaml +++ b/tests/models/cassettes/test_update_transaction.yaml @@ -19,8 +19,7 @@ interactions: method: PUT uri: https://dev.lunchmoney.app/v1/transactions/546452296 response: - body: - string: '{"updated":true}' + content: '{"updated":true}' headers: Access-Control-Allow-Credentials: - 'true' @@ -48,7 +47,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/cassettes/test_upsert_budget.yaml b/tests/models/cassettes/test_upsert_budget.yaml index e90cecb4..9a3b24e8 100644 --- a/tests/models/cassettes/test_upsert_budget.yaml +++ b/tests/models/cassettes/test_upsert_budget.yaml @@ -19,8 +19,7 @@ interactions: method: PUT uri: https://dev.lunchmoney.app/v1/budgets response: - body: - string: '{"category_group":null}' + content: '{"category_group":null}' headers: Access-Control-Allow-Credentials: - 'true' @@ -48,7 +47,6 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/models/test_transactions.py b/tests/models/test_transactions.py index 1742dac3..0adad461 100644 --- a/tests/models/test_transactions.py +++ b/tests/models/test_transactions.py @@ -130,3 +130,16 @@ def test_unsplit_transaction(lunch_money_obj: LunchMoney): parent_ids=transaction_ids, remove_parents=True ) assert len(response) == 3 + + +@lunchable_cassette +def test_get_uncleared_transactions(lunch_money_obj: LunchMoney) -> None: + """ + Get uncleared transactions + + Enum values previously weren't getting JSON encoded + """ + uncleared_transactions = lunch_money_obj.get_transactions(status="uncleared") + assert len(uncleared_transactions) >= 1 + for transaction in uncleared_transactions: + assert isinstance(transaction, TransactionObject) diff --git a/tests/plugins/pushlunch/cassettes/test_post_transaction.yaml b/tests/plugins/pushlunch/cassettes/test_post_transaction.yaml index ecd85be7..0807e7c1 100644 --- a/tests/plugins/pushlunch/cassettes/test_post_transaction.yaml +++ b/tests/plugins/pushlunch/cassettes/test_post_transaction.yaml @@ -17,8 +17,7 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/assets response: - body: - string: '{"assets":[{"id":49335,"type_name":"cash","subtype_name":"checking","name":"Test Account","display_name":null,"balance":"-16513.5500","balance_as_of":"2023-03-07T02:43:48.383Z","closed_on":null,"currency":"usd","institution_name":null,"exclude_transactions":false,"created_at":"2023-03-07T02:05:23.670Z"},{"id":78214,"type_name":"cash","subtype_name":null,"name":"test-account-1","display_name":"Test Account #1","balance":"5.2000","balance_as_of":"2023-12-15T02:26:08.599Z","closed_on":null,"currency":"usd","institution_name":"Test Institution","exclude_transactions":false,"created_at":"2023-12-15T02:24:12.158Z"}]}' + content: '{"assets":[{"id":49335,"type_name":"cash","subtype_name":"checking","name":"Test Account","display_name":null,"balance":"-16513.5500","balance_as_of":"2023-03-07T02:43:48.383Z","closed_on":null,"currency":"usd","institution_name":null,"exclude_transactions":false,"created_at":"2023-03-07T02:05:23.670Z"},{"id":78214,"type_name":"cash","subtype_name":null,"name":"test-account-1","display_name":"Test Account #1","balance":"5.2000","balance_as_of":"2023-12-15T02:26:08.599Z","closed_on":null,"currency":"usd","institution_name":"Test Institution","exclude_transactions":false,"created_at":"2023-12-15T02:24:12.158Z"}]}' headers: Access-Control-Allow-Credentials: - 'true' @@ -46,9 +45,8 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 - request: body: headers: @@ -67,50 +65,7 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/plaid_accounts response: - body: - string: | - { - "plaid_accounts": [ - { - "id": 71394, - "date_linked": "2023-12-15", - "name": "Chase - Freedom", - "display_name": "Chase Freedom", - "type": "credit", - "subtype": "creditcard", - "mask": "5678", - "institution_name": "Chase", - "status": "active", - "limit": 12345, - "balance": "123.0900", - "currency": "usd", - "balance_last_update": "2023-12-14T15:55:00.753Z", - "import_start_date": "2023-02-06", - "last_import": "2023-12-14T15:55:03.163Z", - "last_fetch": "2023-12-14T15:55:03.301Z", - "plaid_last_successful_update": "2023-12-13T15:51:37.490Z" - }, - { - "id": 71395, - "date_linked": "2023-12-15", - "name": "Chase - Sapphire", - "display_name": "Chase Sapphire", - "type": "credit", - "subtype": "creditcard", - "mask": "1234", - "institution_name": "Chase", - "status": "active", - "limit": 12345, - "balance": "456.0900", - "currency": "usd", - "balance_last_update": "2023-12-14T15:55:00.753Z", - "import_start_date": "2023-02-06", - "last_import": "2023-12-14T15:55:03.163Z", - "last_fetch": "2023-12-14T15:55:03.301Z", - "plaid_last_successful_update": "2023-12-13T15:51:37.490Z" - } - ] - } + content: '{"plaid_accounts": [{"id": 71394, "date_linked": "2023-12-15", "name": "Chase - Freedom", "display_name": "Chase Freedom", "type": "credit", "subtype": "creditcard", "mask": "5678", "institution_name": "Chase", "status": "active", "limit": 12345, "balance": "123.0900", "currency": "usd", "balance_last_update": "2023-12-14T15:55:00.753Z", "import_start_date": "2023-02-06", "last_import": "2023-12-14T15:55:03.163Z", "last_fetch": "2023-12-14T15:55:03.301Z", "plaid_last_successful_update": "2023-12-13T15:51:37.490Z"}, {"id": 71395, "date_linked": "2023-12-15", "name": "Chase - Sapphire", "display_name": "Chase Sapphire", "type": "credit", "subtype": "creditcard", "mask": "1234", "institution_name": "Chase", "status": "active", "limit": 12345, "balance": "456.0900", "currency": "usd", "balance_last_update": "2023-12-14T15:55:00.753Z", "import_start_date": "2023-02-06", "last_import": "2023-12-14T15:55:03.163Z", "last_fetch": "2023-12-14T15:55:03.301Z", "plaid_last_successful_update": "2023-12-13T15:51:37.490Z"}]}' headers: Access-Control-Allow-Credentials: - 'true' @@ -138,9 +93,8 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 - request: body: headers: @@ -159,8 +113,7 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/categories response: - body: - string: '{"categories":[{"id":658761,"name":"Another Another Test Category","description":null,"is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-12-15T02:42:01.147Z","created_at":"2023-12-15T02:42:01.147Z","is_group":false,"group_id":658694,"archived":false,"archived_on":null,"order":null},{"id":443128,"name":"Groceries","description":"Test Category Description Updated","is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:27.268Z","created_at":"2023-03-07T02:10:27.268Z","is_group":false,"group_id":658694,"archived":false,"archived_on":null,"order":null},{"id":443125,"name":"Home","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:09:42.960Z","created_at":"2023-03-07T02:09:42.960Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443129,"name":"Income","description":null,"is_income":true,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:40:15.216Z","created_at":"2023-03-07T02:40:15.216Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443127,"name":"Personal Care","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:17.225Z","created_at":"2023-03-07T02:10:17.225Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443126,"name":"Shopping","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:12.260Z","created_at":"2023-03-07T02:10:12.260Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":658693,"name":"Test Category","description":"Test Category Description","is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-12-15T02:32:23.352Z","created_at":"2023-12-15T02:32:23.352Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":658694,"name":"Test Category Group","description":"Test Category Group!!","is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-12-15T02:32:24.849Z","created_at":"2023-12-15T02:32:24.849Z","is_group":true,"group_id":null,"archived":false,"archived_on":null,"order":null,"children":[{"id":658761,"name":"Another Another Test Category","description":null,"is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-12-15T02:42:01.147Z","created_at":"2023-12-15T02:42:01.147Z","is_group":false,"group_id":658694,"archived":false,"archived_on":null,"order":null},{"id":443128,"name":"Groceries","description":"Test Category Description Updated","is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:27.268Z","created_at":"2023-03-07T02:10:27.268Z","is_group":false,"group_id":658694,"archived":false,"archived_on":null,"order":null}]}]}' + content: '{"categories":[{"id":658761,"name":"Another Another Test Category","description":null,"is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-12-15T02:42:01.147Z","created_at":"2023-12-15T02:42:01.147Z","is_group":false,"group_id":658694,"archived":false,"archived_on":null,"order":null},{"id":443128,"name":"Groceries","description":"Test Category Description Updated","is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:27.268Z","created_at":"2023-03-07T02:10:27.268Z","is_group":false,"group_id":658694,"archived":false,"archived_on":null,"order":null},{"id":443125,"name":"Home","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:09:42.960Z","created_at":"2023-03-07T02:09:42.960Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443129,"name":"Income","description":null,"is_income":true,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:40:15.216Z","created_at":"2023-03-07T02:40:15.216Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443127,"name":"Personal Care","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:17.225Z","created_at":"2023-03-07T02:10:17.225Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443126,"name":"Shopping","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:12.260Z","created_at":"2023-03-07T02:10:12.260Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":658693,"name":"Test Category","description":"Test Category Description","is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-12-15T02:32:23.352Z","created_at":"2023-12-15T02:32:23.352Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":658694,"name":"Test Category Group","description":"Test Category Group!!","is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-12-15T02:32:24.849Z","created_at":"2023-12-15T02:32:24.849Z","is_group":true,"group_id":null,"archived":false,"archived_on":null,"order":null,"children":[{"id":658761,"name":"Another Another Test Category","description":null,"is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-12-15T02:42:01.147Z","created_at":"2023-12-15T02:42:01.147Z","is_group":false,"group_id":658694,"archived":false,"archived_on":null,"order":null},{"id":443128,"name":"Groceries","description":"Test Category Description Updated","is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:27.268Z","created_at":"2023-03-07T02:10:27.268Z","is_group":false,"group_id":658694,"archived":false,"archived_on":null,"order":null}]}]}' headers: Access-Control-Allow-Credentials: - 'true' @@ -190,9 +143,8 @@ interactions: - Express content-length: - '3062' - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 - request: body: headers: @@ -211,8 +163,7 @@ interactions: method: POST uri: https://api.pushover.net/1/messages.json?html=1&message=%3Cb%3EPayee%3A%3C%2Fb%3E+%3Ci%3ETest%3C%2Fi%3E%0A%3Cb%3EAmount%3A%3C%2Fb%3E+%3Ci%3E%24+1.00%3C%2Fi%3E%0A%3Cb%3EDate%3A%3C%2Fb%3E+%3Ci%3ESunday+September+19%2C+2021%3C%2Fi%3E%0A%3Cb%3ECategory%3A%3C%2Fb%3E+%3Ci%3EAnother+Another+Test+Category%3C%2Fi%3E%0A%3Cb%3EAccount%3A%3C%2Fb%3E+%3Ci%3ETest+Account%3C%2Fi%3E%0A%3Cb%3ECurrency%3A%3C%2Fb%3E+%3Ci%3EUSD%3C%2Fi%3E%0A%3Cb%3EStatus%3A%3C%2Fb%3E+%3Ci%3EUncleared%3C%2Fi%3E%0A%3Cb%3ENotes%3A%3C%2Fb%3E+%3Ci%3EExample+Test+Notification+from+lunchable%3C%2Fi%3E%0A%0A%3Ca+href%3D%22https%3A%2F%2Fmy.lunchmoney.app%2Ftransactions%2F2021%2F09%3Fstatus%3Dunreviewed%22%3E%3Cb%3EUncleared+Transactions+from+this+Period%3C%2Fb%3E%3C%2Fa%3E&title=Lunch+Money+Transaction&token=XXXXXXXXXX&user=XXXXXXXXXX response: - body: - string: '{"status":1,"request":"b80ebc1d-6ae8-430e-98c1-4cb53791f420"}' + content: '{"status":1,"request":"b80ebc1d-6ae8-430e-98c1-4cb53791f420"}' headers: Access-Control-Allow-Headers: - X-Requested-With, X-Prototype-Version, Origin, Accept, Content-Type, X-CSRF-Token, X-Pushover-App, Authorization @@ -260,7 +211,6 @@ interactions: - '0.012594' X-XSS-Protection: - 1; mode=block - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/plugins/pushlunch/cassettes/test_send_notification.yaml b/tests/plugins/pushlunch/cassettes/test_send_notification.yaml index 0887ce7e..d2d4034c 100644 --- a/tests/plugins/pushlunch/cassettes/test_send_notification.yaml +++ b/tests/plugins/pushlunch/cassettes/test_send_notification.yaml @@ -17,8 +17,7 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/assets response: - body: - string: '{"assets":[{"id":21845,"type_name":"cash","subtype_name":"digital wallet (paypal, venmo)","name":"Splitwise Balance","display_name":"Splitwise","balance":"176.6700","balance_as_of":"2021-11-15T17:44:52.277Z","currency":"usd","closed_on":null,"institution_name":"Splitwise","created_at":"2021-08-28T16:06:02.701Z"},{"id":23043,"type_name":"cash","subtype_name":"digital wallet (paypal, venmo)","name":"Test Account","display_name":"Test Account","balance":"181.7100","balance_as_of":"2021-11-02T22:27:05.311Z","currency":"usd","closed_on":null,"institution_name":"Test","created_at":"2021-09-20T05:32:29.060Z"}]}' + content: '{"assets":[{"id":21845,"type_name":"cash","subtype_name":"digital wallet (paypal, venmo)","name":"Splitwise Balance","display_name":"Splitwise","balance":"176.6700","balance_as_of":"2021-11-15T17:44:52.277Z","currency":"usd","closed_on":null,"institution_name":"Splitwise","created_at":"2021-08-28T16:06:02.701Z"},{"id":23043,"type_name":"cash","subtype_name":"digital wallet (paypal, venmo)","name":"Test Account","display_name":"Test Account","balance":"181.7100","balance_as_of":"2021-11-02T22:27:05.311Z","currency":"usd","closed_on":null,"institution_name":"Test","created_at":"2021-09-20T05:32:29.060Z"}]}' headers: Access-Control-Allow-Credentials: - 'true' @@ -40,9 +39,8 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 - request: body: headers: @@ -61,32 +59,12 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/plaid_accounts response: - body: - string: !!binary | - H4sIAAAAAAAAA+WY74+aSBjH/xXCq/bikvkJDO+s2q45Tz1h90UvjZkF0k5ENDCYmKb/+z1Yb8Wu - suxC09yd8YV5mGfG+eT7/OKruU2kipYyDDdFqnPT++urqSLTY5gL1jMjqeNlotJVDDaTIIJvMHxt - s2emch2D7V22WcWZ/BwbN8botyCTUQwPI5XDxvvlcRE8WPSHI+O9SmUaKpkY4zRSOxUV8LOyA8aM - gLfeb0svle7iXK/jVIMtLx6O5od/1oN1LfMVmI5+Ks210oVWm/TqyeVWWuoCrmrKUKtduU0ic71U - 6+0m06aXFknSMx9kAg7lFshC8IFVYZFlcRruwVbkkfm4ZnlwL7YlrColHmDbI8KjyOLU+Vieo9bq - eMK33iNohzcBPZBbpQHXLC1R3wOVIruAurrstOiILsziSJ3T/G4yQplFJ54CY3SZZ2X750me7sEC - jD3KPU4tF9sfzSpf4iLLbkcYU0swWkPYbUJ45M/nT4E+q8dcb8KVAS5pFaDrXgb4XkVxovS+Sg+0 - +ROViG6IEyDbo9SjroVInRJRE063myKPDV/uVPo5rwMWxdtNrvQm258De/Q80nIRuhK+/STZG+9k - unqB2BAOMPI494htCdc9F5twkAtaaRfPzBIOrqEomlAcT4fj+/Hwrj95heYu5MCXSa6Z4LCDmG3x - 1rgoIjW4SCNcqY4zQGEMvsThCvTzCuGFJ9dH5RHcnfJO+ci1iHDOlceQcCxbtFeeXYPSaYJyMr6f - TT/MjNtRfxLcvkJ9DOFVhaHj8H9jrsNNWP2h8jBO4MAYkl63Oe9aiX258uDW7HBr5EG4Ys7OlQfR - B2aB20uP1eBs1C3+WahwlatkF2d1EJv2KdR2WAd9SucdX9mPUHEdltuozi5GfrAYD4LR0PCD2eB3 - 4246Dvz/d4diN6qt/hcJcum2VBDErqS5iwF7jdj3/4vcG+IGmMN9Pcwsm/LzkMXYhhLitkMJ5Ybz - moilL0DZYeYTmNoddns8IMijwuPYQjb6AaPLmUV4+8TnXscoGk1v/iEE53AiDG/BcDZ4SvLpkFxx - elP6vG04IV+K9586IlOKBe9iTGboGmib8Gahf8iU87vF4Lbvj4z5pD/9JRnzuVYRBZgdot+x2I+t - Yvs3DmXLXdMnuo16n1JyxpvJ/YfZW2Ph39UG/3+/8jh2I2ajSR+w9YzxdGC1bq1B9U7XMx0hSAiL - k7YCI+JJbfn07W/qjC1HUBQAAA== + content: '{"plaid_accounts": [{"id": 71394, "date_linked": "2023-12-15", "name": "Chase - Freedom", "display_name": "Chase Freedom", "type": "credit", "subtype": "creditcard", "mask": "5678", "institution_name": "Chase", "status": "active", "limit": 12345, "balance": "123.0900", "currency": "usd", "balance_last_update": "2023-12-14T15:55:00.753Z", "import_start_date": "2023-02-06", "last_import": "2023-12-14T15:55:03.163Z", "last_fetch": "2023-12-14T15:55:03.301Z", "plaid_last_successful_update": "2023-12-13T15:51:37.490Z"}, {"id": 71395, "date_linked": "2023-12-15", "name": "Chase - Sapphire", "display_name": "Chase Sapphire", "type": "credit", "subtype": "creditcard", "mask": "1234", "institution_name": "Chase", "status": "active", "limit": 12345, "balance": "456.0900", "currency": "usd", "balance_last_update": "2023-12-14T15:55:00.753Z", "import_start_date": "2023-02-06", "last_import": "2023-12-14T15:55:03.163Z", "last_fetch": "2023-12-14T15:55:03.301Z", "plaid_last_successful_update": "2023-12-13T15:51:37.490Z"}]}' headers: Access-Control-Allow-Credentials: - 'true' Connection: - keep-alive - Content-Encoding: - - gzip Content-Type: - application/json; charset=utf-8 Date: @@ -103,9 +81,8 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 - request: body: headers: @@ -124,32 +101,12 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/categories response: - body: - string: !!binary | - H4sIAAAAAAAAA82YXU/bMBSG/0qU6zazHdtpfAcM2C6QppFp0qapMo3bRqRx5SRsCPHf534oLpCs - NoWlEjfFb1U/Pu85PscP/oRXYiZVJkqf/Xzws9RnCMUwRAO/4AvhM/8kn8i5zAfeKVelP/BTUU5U - tqwyWfisqPN84GflOCsmciWf8rwUA1/8meR1KsZTJRfjmzqdiap9rZKV/m+zVi9TvaF0zLXcRwDB - IYiGCCUAMRAxCAOCRz/0JiZKWOn0zmZK1svmB9afxivM1dYfBzvIYYN8yotb70KII8Al1A53o3PA - pdjgZnneJyomDMAAArQH9YnOFjXCOIoa1DNezr0P3kly9Zx3s/Q9q+ap4r/5+kDekx7qP5JAyjBm - EAQjAtrp23UuvjaBPpPTqRDe9Vwuj8DaNLSz9kZnS0xRTGFD/FHcVC8i/a2oFJ/citQ7UyLNKu+M - q9TbSt815mCIaAIwwzGDOKCo4wTadS4xJ80JnBeVUBXPioUoXhzF/w961GHzdp0tMsEoig3ynUbt - w+DxMAQJAIzEOluDOO6q3a06a4NDEpuUPt/sMH1h8ktRCMVz7e31BX/vTaXyTtd43vpLpdY5FLlK - 1V0HsllqtztKIGEIsjAORnFXiWvVOdgdg+Y8LqRcpXKe3Ql137vdKSBWdt/qXDKcNsiXvBx4ieJF - uZQ609eofYOTkWVxHzmXtpEBz6a9pPkzhM40b9W5oJqSdqnkRKy79L5xKbCr4FudSxaba/uTRhl4 - J3Ulj4A3tuSNXXlNeD9vYPaxttRgi/JsTUqxHelG50JqcvYLv181ItuCNRXqoAC/4lJ6DkPs5smt - zgXajNBfhCplsb6M1f4ov7ujoV3B2upckMMd5CMozRTtGymf6GxJMYojQ/pVZIubWpXi4Ab7NW4e - DVG8ap1gpLvggEZdbm7VuTwXkB3gotIz9JVuNmZ8dpifD0lgPGIgDML9zwa7Ohc34x3ksuK1rlhH - YerI0tSRa79h3km+ZhpyzlVWzHoHJl1zQ7vOJcLG1Ncinw6zxVLJu8MT+U3CHNp10FudC7UZHVYv - QctjiDENLU0dupqamkp9vZC3fV6/GKxqr55g9hWsXZ31EwgkO/mb6ILVjP4v3gaerOpp2ay9ReH+ - 1/sIAgkKGaaMkABFXZW7Vefi8J2DUPxO5P37m1h2IsSVlZi3D/N43XdTTS1nJmo1M/16/Aun4gU/ - qBoAAA== + content: '{"categories":[{"id":443128,"name":"Groceries","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:27.268Z","created_at":"2023-03-07T02:10:27.268Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443125,"name":"Home","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:09:42.960Z","created_at":"2023-03-07T02:09:42.960Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443129,"name":"Income","description":null,"is_income":true,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:40:15.216Z","created_at":"2023-03-07T02:40:15.216Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443127,"name":"Personal Care","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:17.225Z","created_at":"2023-03-07T02:10:17.225Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443126,"name":"Shopping","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:12.260Z","created_at":"2023-03-07T02:10:12.260Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null}]}' headers: Access-Control-Allow-Credentials: - 'true' Connection: - keep-alive - Content-Encoding: - - gzip Content-Type: - application/json; charset=utf-8 Date: @@ -166,9 +123,8 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 - request: body: headers: @@ -187,10 +143,7 @@ interactions: method: POST uri: https://api.pushover.net/1/messages.json?message=This+is+a+test+notification+from+lunchable.&title=Test&token=XXXXXXXXXX&user=XXXXXXXXXX response: - body: - string: !!binary | - H4sIAAAAAAAAAwTBMRKAMAgEwL9cLQUMiZjfqJA+klSOf3f3Rc5zrkTjDU+MFTnREGpaS99Jiiqp - mZKFHGTOfN3uEr3i+wEAAP//AwCOIOahPQAAAA== + content: '{"status":1,"request":"cc6ffda3-e0b0-45d8-9795-738acb1fee76"}' headers: Access-Control-Allow-Headers: - X-Requested-With, X-Prototype-Version, Origin, Accept, Content-Type, X-CSRF-Token, X-Pushover-App, Authorization @@ -208,8 +161,6 @@ interactions: - max-age=0, private, must-revalidate Connection: - keep-alive - Content-Encoding: - - gzip Content-Type: - application/json; charset=utf-8 Date: @@ -249,7 +200,6 @@ interactions: - '0.066568' X-XSS-Protection: - 1; mode=block - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 version: 1 diff --git a/tests/plugins/splitlunch/cassettes/test_update_balance.yaml b/tests/plugins/splitlunch/cassettes/test_update_balance.yaml index 9f7b65a3..b4d216b8 100644 --- a/tests/plugins/splitlunch/cassettes/test_update_balance.yaml +++ b/tests/plugins/splitlunch/cassettes/test_update_balance.yaml @@ -129,8 +129,7 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/tags response: - body: - string: '[{"id":22215,"name":"Wedding","description":null},{"id":21559,"name":"test","description":null},{"id":24194,"name":"SplitLunchDirectImport","description":null},{"id":21639,"name":"SplitLunch","description":"Tag to Create Splitwise Transactions from Lunch Money"},{"id":23474,"name":"Splitwise","description":null},{"id":22178,"name":"SplitLunchImport","description":null}]' + content: '[{"id":22215,"name":"Wedding","description":null},{"id":21559,"name":"test","description":null},{"id":24194,"name":"SplitLunchDirectImport","description":null},{"id":21639,"name":"SplitLunch","description":"Tag to Create Splitwise Transactions from Lunch Money"},{"id":23474,"name":"Splitwise","description":null},{"id":22178,"name":"SplitLunchImport","description":null}]' headers: Access-Control-Allow-Credentials: - 'true' @@ -152,9 +151,8 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 - request: body: headers: @@ -173,8 +171,7 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/assets response: - body: - string: '{"assets":[{"id":21845,"type_name":"cash","subtype_name":"digital wallet (paypal, venmo)","name":"Splitwise Balance","display_name":"Splitwise","balance":"176.6700","balance_as_of":"2021-11-16T02:17:52.209Z","currency":"usd","closed_on":null,"institution_name":"Splitwise","created_at":"2021-08-28T16:06:02.701Z"},{"id":23043,"type_name":"cash","subtype_name":"digital wallet (paypal, venmo)","name":"Test Account","display_name":"Test Account","balance":"181.7100","balance_as_of":"2021-11-02T22:27:05.311Z","currency":"usd","closed_on":null,"institution_name":"Test","created_at":"2021-09-20T05:32:29.060Z"}]}' + content: '{"assets":[{"id":21845,"type_name":"cash","subtype_name":"digital wallet (paypal, venmo)","name":"Splitwise Balance","display_name":"Splitwise","balance":"176.6700","balance_as_of":"2021-11-16T02:17:52.209Z","currency":"usd","closed_on":null,"institution_name":"Splitwise","created_at":"2021-08-28T16:06:02.701Z"},{"id":23043,"type_name":"cash","subtype_name":"digital wallet (paypal, venmo)","name":"Test Account","display_name":"Test Account","balance":"181.7100","balance_as_of":"2021-11-02T22:27:05.311Z","currency":"usd","closed_on":null,"institution_name":"Test","created_at":"2021-09-20T05:32:29.060Z"}]}' headers: Access-Control-Allow-Credentials: - 'true' @@ -196,9 +193,8 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 - request: body: headers: @@ -217,32 +213,12 @@ interactions: method: GET uri: https://dev.lunchmoney.app/v1/categories response: - body: - string: !!binary | - H4sIAAAAAAAAA82YXU/bMBSG/0qU6zazHdtpfAcM2C6QppFp0qapMo3bRqRx5SRsCPHf534oLpCs - NoWlEjfFb1U/Pu85PscP/oRXYiZVJkqf/Xzws9RnCMUwRAO/4AvhM/8kn8i5zAfeKVelP/BTUU5U - tqwyWfisqPN84GflOCsmciWf8rwUA1/8meR1KsZTJRfjmzqdiap9rZKV/m+zVi9TvaF0zLXcRwDB - IYiGCCUAMRAxCAOCRz/0JiZKWOn0zmZK1svmB9afxivM1dYfBzvIYYN8yotb70KII8Al1A53o3PA - pdjgZnneJyomDMAAArQH9YnOFjXCOIoa1DNezr0P3kly9Zx3s/Q9q+ap4r/5+kDekx7qP5JAyjBm - EAQjAtrp23UuvjaBPpPTqRDe9Vwuj8DaNLSz9kZnS0xRTGFD/FHcVC8i/a2oFJ/citQ7UyLNKu+M - q9TbSt815mCIaAIwwzGDOKCo4wTadS4xJ80JnBeVUBXPioUoXhzF/w961GHzdp0tMsEoig3ynUbt - w+DxMAQJAIzEOluDOO6q3a06a4NDEpuUPt/sMH1h8ktRCMVz7e31BX/vTaXyTtd43vpLpdY5FLlK - 1V0HsllqtztKIGEIsjAORnFXiWvVOdgdg+Y8LqRcpXKe3Ql137vdKSBWdt/qXDKcNsiXvBx4ieJF - uZQ609eofYOTkWVxHzmXtpEBz6a9pPkzhM40b9W5oJqSdqnkRKy79L5xKbCr4FudSxaba/uTRhl4 - J3Ulj4A3tuSNXXlNeD9vYPaxttRgi/JsTUqxHelG50JqcvYLv181ItuCNRXqoAC/4lJ6DkPs5smt - zgXajNBfhCplsb6M1f4ov7ujoV3B2upckMMd5CMozRTtGymf6GxJMYojQ/pVZIubWpXi4Ab7NW4e - DVG8ap1gpLvggEZdbm7VuTwXkB3gotIz9JVuNmZ8dpifD0lgPGIgDML9zwa7Ohc34x3ksuK1rlhH - YerI0tSRa79h3km+ZhpyzlVWzHoHJl1zQ7vOJcLG1Ncinw6zxVLJu8MT+U3CHNp10FudC7UZHVYv - QctjiDENLU0dupqamkp9vZC3fV6/GKxqr55g9hWsXZ31EwgkO/mb6ILVjP4v3gaerOpp2ay9ReH+ - 1/sIAgkKGaaMkABFXZW7Vefi8J2DUPxO5P37m1h2IsSVlZi3D/N43XdTTS1nJmo1M/16/Aun4gU/ - qBoAAA== + content: '{"categories":[{"id":658761,"name":"Another Another Test Category","description":null,"is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-12-15T02:42:01.147Z","created_at":"2023-12-15T02:42:01.147Z","is_group":false,"group_id":658694,"archived":false,"archived_on":null,"order":null},{"id":443128,"name":"Groceries","description":"Test Category Description Updated","is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:27.268Z","created_at":"2023-03-07T02:10:27.268Z","is_group":false,"group_id":658694,"archived":false,"archived_on":null,"order":null},{"id":443125,"name":"Home","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:09:42.960Z","created_at":"2023-03-07T02:09:42.960Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443129,"name":"Income","description":null,"is_income":true,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:40:15.216Z","created_at":"2023-03-07T02:40:15.216Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443127,"name":"Personal Care","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:17.225Z","created_at":"2023-03-07T02:10:17.225Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":443126,"name":"Shopping","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:12.260Z","created_at":"2023-03-07T02:10:12.260Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":660672,"name":"Splitwise","description":null,"is_income":false,"exclude_from_budget":false,"exclude_from_totals":false,"updated_at":"2023-12-15T20:45:04.146Z","created_at":"2023-12-15T20:45:04.146Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":0},{"id":658693,"name":"Test Category","description":"Test Category Description","is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-12-15T02:32:23.352Z","created_at":"2023-12-15T02:32:23.352Z","is_group":false,"group_id":null,"archived":false,"archived_on":null,"order":null},{"id":658694,"name":"Test Category Group","description":"Test Category Group!!","is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-12-15T02:32:24.849Z","created_at":"2023-12-15T02:32:24.849Z","is_group":true,"group_id":null,"archived":false,"archived_on":null,"order":null,"children":[{"id":658761,"name":"Another Another Test Category","description":null,"is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-12-15T02:42:01.147Z","created_at":"2023-12-15T02:42:01.147Z","is_group":false,"group_id":658694,"archived":false,"archived_on":null,"order":null},{"id":443128,"name":"Groceries","description":"Test Category Description Updated","is_income":false,"exclude_from_budget":true,"exclude_from_totals":false,"updated_at":"2023-03-07T02:10:27.268Z","created_at":"2023-03-07T02:10:27.268Z","is_group":false,"group_id":658694,"archived":false,"archived_on":null,"order":null}]}]}' headers: Access-Control-Allow-Credentials: - 'true' Connection: - keep-alive - Content-Encoding: - - gzip Content-Type: - application/json; charset=utf-8 Date: @@ -259,9 +235,8 @@ interactions: - 1.1 vegur X-Powered-By: - Express - status: - code: 200 - message: OK + http_version: HTTP/1.1 + status_code: 200 - request: body: headers: