lunchmoney-python 2.9.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. lunchmoney/__init__.py +205 -0
  2. lunchmoney/api/__init__.py +16 -0
  3. lunchmoney/api/categories_api.py +1499 -0
  4. lunchmoney/api/manual_accounts_api.py +1479 -0
  5. lunchmoney/api/me_api.py +293 -0
  6. lunchmoney/api/plaid_accounts_api.py +909 -0
  7. lunchmoney/api/recurring_items_api.py +702 -0
  8. lunchmoney/api/summary_api.py +434 -0
  9. lunchmoney/api/tags_api.py +1465 -0
  10. lunchmoney/api/transactions_api.py +914 -0
  11. lunchmoney/api/transactions_bulk_api.py +1527 -0
  12. lunchmoney/api/transactions_files_api.py +891 -0
  13. lunchmoney/api/transactions_group_api.py +601 -0
  14. lunchmoney/api/transactions_split_api.py +616 -0
  15. lunchmoney/api_client.py +805 -0
  16. lunchmoney/api_response.py +21 -0
  17. lunchmoney/configuration.py +620 -0
  18. lunchmoney/exceptions.py +217 -0
  19. lunchmoney/models/__init__.py +84 -0
  20. lunchmoney/models/account_type_enum.py +46 -0
  21. lunchmoney/models/aligned_category_totals_object.py +108 -0
  22. lunchmoney/models/aligned_summary_category_object.py +110 -0
  23. lunchmoney/models/aligned_summary_response_object.py +104 -0
  24. lunchmoney/models/category_object.py +146 -0
  25. lunchmoney/models/child_category_object.py +141 -0
  26. lunchmoney/models/child_transaction_object.py +219 -0
  27. lunchmoney/models/create_category_request_object.py +137 -0
  28. lunchmoney/models/create_category_request_object_children_inner.py +159 -0
  29. lunchmoney/models/create_manual_account_request_object.py +138 -0
  30. lunchmoney/models/create_manual_account_request_object_balance.py +145 -0
  31. lunchmoney/models/create_new_transactions_request.py +103 -0
  32. lunchmoney/models/create_tag_request_object.py +112 -0
  33. lunchmoney/models/currency_enum.py +198 -0
  34. lunchmoney/models/delete_category_response_with_dependencies.py +94 -0
  35. lunchmoney/models/delete_category_response_with_dependencies_dependents.py +98 -0
  36. lunchmoney/models/delete_tag_response_with_dependencies.py +94 -0
  37. lunchmoney/models/delete_tag_response_with_dependencies_dependents.py +90 -0
  38. lunchmoney/models/delete_transactions_request.py +89 -0
  39. lunchmoney/models/error_response_object.py +98 -0
  40. lunchmoney/models/error_response_object_errors_inner.py +101 -0
  41. lunchmoney/models/get_all_categories200_response.py +96 -0
  42. lunchmoney/models/get_all_manual_accounts200_response.py +96 -0
  43. lunchmoney/models/get_all_plaid_accounts200_response.py +96 -0
  44. lunchmoney/models/get_all_recurring200_response.py +96 -0
  45. lunchmoney/models/get_all_tags200_response.py +96 -0
  46. lunchmoney/models/get_all_transactions200_response.py +100 -0
  47. lunchmoney/models/get_all_transactions_created_since_parameter.py +145 -0
  48. lunchmoney/models/get_budget_summary200_response.py +138 -0
  49. lunchmoney/models/get_transaction_attachment_url200_response.py +91 -0
  50. lunchmoney/models/group_transactions_request.py +122 -0
  51. lunchmoney/models/insert_transaction_object.py +164 -0
  52. lunchmoney/models/insert_transaction_object_amount.py +145 -0
  53. lunchmoney/models/insert_transactions_response_object.py +106 -0
  54. lunchmoney/models/manual_account_object.py +158 -0
  55. lunchmoney/models/non_aligned_category_totals_object.py +94 -0
  56. lunchmoney/models/non_aligned_summary_category_object.py +94 -0
  57. lunchmoney/models/non_aligned_summary_response_object.py +104 -0
  58. lunchmoney/models/plaid_account_object.py +168 -0
  59. lunchmoney/models/recurring_object.py +143 -0
  60. lunchmoney/models/recurring_object_matches.py +105 -0
  61. lunchmoney/models/recurring_object_matches_found_transactions_inner.py +91 -0
  62. lunchmoney/models/recurring_object_overrides.py +92 -0
  63. lunchmoney/models/recurring_object_transaction_criteria.py +149 -0
  64. lunchmoney/models/skipped_existing_external_id_object.py +108 -0
  65. lunchmoney/models/split_transaction_object.py +102 -0
  66. lunchmoney/models/split_transaction_object_amount.py +145 -0
  67. lunchmoney/models/split_transaction_request.py +97 -0
  68. lunchmoney/models/summary_category_occurrence_object.py +126 -0
  69. lunchmoney/models/summary_recurring_transaction_object.py +100 -0
  70. lunchmoney/models/summary_rollover_pool_adjustment_object.py +98 -0
  71. lunchmoney/models/summary_rollover_pool_object.py +98 -0
  72. lunchmoney/models/summary_totals_breakdown_object.py +98 -0
  73. lunchmoney/models/summary_totals_object.py +97 -0
  74. lunchmoney/models/tag_object.py +125 -0
  75. lunchmoney/models/transaction_attachment_object.py +106 -0
  76. lunchmoney/models/transaction_object.py +229 -0
  77. lunchmoney/models/update_category_request_object.py +156 -0
  78. lunchmoney/models/update_manual_account_request_object.py +156 -0
  79. lunchmoney/models/update_manual_account_request_object_balance.py +145 -0
  80. lunchmoney/models/update_tag_request_object.py +126 -0
  81. lunchmoney/models/update_transaction_object.py +228 -0
  82. lunchmoney/models/update_transaction_object_amount.py +145 -0
  83. lunchmoney/models/update_transactions200_response.py +96 -0
  84. lunchmoney/models/update_transactions_request.py +97 -0
  85. lunchmoney/models/update_transactions_request_transactions_inner.py +228 -0
  86. lunchmoney/models/user_object.py +106 -0
  87. lunchmoney/py.typed +0 -0
  88. lunchmoney/rest.py +259 -0
  89. lunchmoney_python-2.9.0.dist-info/METADATA +285 -0
  90. lunchmoney_python-2.9.0.dist-info/RECORD +92 -0
  91. lunchmoney_python-2.9.0.dist-info/WHEEL +5 -0
  92. lunchmoney_python-2.9.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,228 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ Lunch Money API - v2
5
+
6
+ Welcome to the Lunch Money v2 API. A working version of this API is now available through these docs, or directly at: `https://api.lunchmoney.dev/v2` <span class=\"red-text\"><strong>This is in alpha launch of a major API update. It is still subject to change during this alpha review period and bugs may still exist. Users are strongly encouraged to use the mock service or to create a test budget with example data as the first step to interacting with the v2 API.</strong></span> See the [Getting Started Guide](https://alpha.lunchmoney.dev/v2/getting-started) for more information on using a test budget.<br<br> If you are new to the v2 API, you may wish to review the [v2 API Overview of Changes](https://alpha.lunchmoney.dev/v2/changelog). ### Static Mock Server You may also use these docs to explore the API using a static mock server endpoint.<p> This enables users to become familiar with the API without having to create an access token, and eliminates the possibility of modifying real data. <p> To access this endpoint select the second endpoint in the the \"Server\" dropdown to the right. When selected you should see \"Static Mock v2 Lunch Money API Server\".<br> When using this server, set your Bearer token to any string with 11 or more characters. ### Migrating from V1 The v2 API is NOT backwards compatible with the v1 API. Developers are encouraged to review the [Migration Guide](https://alpha.lunchmoney.dev/v2/migration-guide) to understand the changes and plan their migration. ### Acknowledgments If you have been providing feedback on the API during our iterative design process, **THANK YOU**. We are happy to provide the opportunity to finally interact with the working API that was built based on your feedback. ### Useful links: - [Getting Started](https://alpha.lunchmoney.dev/v2/getting-started) - [v2 API Changelog](https://alpha.lunchmoney.dev/v2/changelog) - [Migration Guide](https://alpha.lunchmoney.dev/v2/migration-guide) - [Rate Limits](https://alpha.lunchmoney.dev/v2/rate-limits) - [Current v1 Lunch Money API Documentation](https://lunchmoney.dev) - [Awesome Lunch Money Projects](https://github.com/lunch-money/awesome-lunchmoney?tab=readme-ov-file)
7
+
8
+ The version of the OpenAPI document: 2.8.4
9
+ Contact: devsupport@lunchmoney.app
10
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
11
+
12
+ Do not edit the class manually.
13
+ """ # noqa: E501
14
+
15
+
16
+ from __future__ import annotations
17
+ import pprint
18
+ import re # noqa: F401
19
+ import json
20
+
21
+ from datetime import date, datetime
22
+ from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictFloat, StrictInt, StrictStr, field_validator
23
+ from typing import Any, ClassVar, Dict, List, Optional, Union
24
+ from typing_extensions import Annotated
25
+ from lunchmoney.models.child_transaction_object import ChildTransactionObject
26
+ from lunchmoney.models.currency_enum import CurrencyEnum
27
+ from lunchmoney.models.update_transaction_object_amount import UpdateTransactionObjectAmount
28
+ from typing import Optional, Set
29
+ from typing_extensions import Self
30
+
31
+ class UpdateTransactionsRequestTransactionsInner(BaseModel):
32
+ """
33
+ UpdateTransactionsRequestTransactionsInner
34
+ """ # noqa: E501
35
+ id: StrictInt = Field(description="The ID of the transaction to update")
36
+ var_date: Optional[date] = Field(default=None, description="Date of transaction in ISO 8601 format", alias="date")
37
+ amount: Optional[UpdateTransactionObjectAmount] = None
38
+ currency: Optional[CurrencyEnum] = Field(default=None, description="Three-letter lowercase currency code of the transaction in ISO 4217 format.<br> May not be updated on transactions that belong to a synced account with the \"Allow Modifications to Transactions\" property disabled.")
39
+ recurring_id: Optional[StrictInt] = Field(default=None, description="The unique identifier of the associated recurring item that this transaction matches.")
40
+ payee: Optional[Annotated[str, Field(min_length=0, strict=True, max_length=140)]] = Field(default=None, description="The new payee for the transaction. ")
41
+ category_id: Optional[StrictInt] = Field(default=None, description="Unique identifier of the category for this transaction. Set this to null to clear the transaction's category.")
42
+ notes: Optional[Annotated[str, Field(min_length=0, strict=True, max_length=350)]] = Field(default=None, description="New notes for the transaction. Set this to an empty string to clear the existing notes. ")
43
+ manual_account_id: Optional[StrictInt] = Field(default=None, description="The unique identifier of the manual account associated with this transaction. Set this to null to disassociate the transaction with an account. If set `plaid_account_id` may not also be set to a non null value. Moving an existing transaction to to another account will not work if the transaction belongs to a synced account who's \"Allow Modifications to Transactions\" property is not set.")
44
+ plaid_account_id: Optional[StrictInt] = Field(default=None, description="The unique identifier of the plaid account associated with this transaction. If set `manual_account_id` may not also be set to a non null value. Attempting to modify this on a transaction associated with a Plaid account will not work if the account's \"Allow Modifications to Transactions\" property is not set. Similarly, this cannot be set to an id associated with this type of locked Plaid account.")
45
+ tag_ids: Optional[List[StrictInt]] = Field(default=None, description="A list of tag_ids for the tags associated with this transaction. If set, this property will overwrite any existing tags. Use `additional_tag_ids` to add tags to the existing transaction's tags. Set this to an empty array to remove all tags from a transaction. If set `additional_tag_ids` may not be set.")
46
+ additional_tag_ids: Optional[List[StrictInt]] = Field(default=None, description="A list of tag_ids for the tags associated with this transaction. If set, the tags listed in this property be added to any existing transaction tags. Use `tag_ids` to overwrite or clear transaction tags. If set `tag_ids` may not be set.")
47
+ external_id: Optional[Annotated[str, Field(min_length=0, strict=True, max_length=75)]] = Field(default=None, description="A user-defined external ID for the transaction. The update will fail if the transaction does not also have a `manual_account_id` or if there is already an existing transaction with the same `manual_account_id`/`external_id` combination.")
48
+ custom_metadata: Optional[Dict[str, Any]] = Field(default=None, description="User defined JSON data that can be set or cleared via the API.")
49
+ status: Optional[StrictStr] = Field(default=None, description="Status of the transaction, may be one of: - `reviewed`: User has reviewed the transaction, or it was automatically marked as reviewed due to reviewed recurring_item logic - `unreviewed`: User has not reviewed the transaction and it does not match any reviewed recurring_items. ")
50
+ to_base: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="System defined amount of this transaction in the user's primary currency. Ignored if set. Use `amount` to update the amount in the transaction.")
51
+ is_pending: Optional[StrictBool] = Field(default=None, description="System defined flag set for pending transactions. Ignored if set.")
52
+ plaid_metadata: Optional[Dict[str, Any]] = Field(default=None, description="System set metadata from a Plaid account sync. Ignored if set.")
53
+ created_at: Optional[datetime] = Field(default=None, description="System defined date and time of when the transaction was created. Ignored if set.")
54
+ updated_at: Optional[datetime] = Field(default=None, description="System defined date and time of when the transaction was last updated. Ignored if set.")
55
+ is_split_parent: Optional[StrictBool] = Field(default=None, description="System defined boolean indicating if this transaction was split. To split or unsplit a transaction use the `/transactions/split` endpoint. Ignored if set.")
56
+ children: Optional[List[ChildTransactionObject]] = Field(default=None, description="An array of child transactions that exists when a transaction has been split or if the transaction is a group. Split")
57
+ split_parent_id: Optional[StrictInt] = Field(default=None, description="A transaction ID if this is a split transaction. Split transactions may not be modified this API. Use the `transactions/split` endpoint instead. Ignored if set.")
58
+ is_group_parent: Optional[StrictBool] = Field(default=None, description="System defined boolean indicating if this transaction represents a group of transactions. Grouped transactions may not be modified with this API. Use the `transactions/group` endpoint instead. Ignored if set.")
59
+ group_parent_id: Optional[StrictInt] = Field(default=None, description="A transaction group ID if this transaction is part of a group. Grouped transactions may not be modified with this API. Use the `transactions/group` endpoint instead. Ignored if set.")
60
+ source: Optional[StrictStr] = Field(default=None, description="System defined original source of the transaction. Ignored if set. ")
61
+ __properties: ClassVar[List[str]] = ["id", "date", "amount", "currency", "recurring_id", "payee", "category_id", "notes", "manual_account_id", "plaid_account_id", "tag_ids", "additional_tag_ids", "external_id", "custom_metadata", "status", "to_base", "is_pending", "plaid_metadata", "created_at", "updated_at", "is_split_parent", "children", "split_parent_id", "is_group_parent", "group_parent_id", "source"]
62
+
63
+ @field_validator('status')
64
+ def status_validate_enum(cls, value):
65
+ """Validates the enum"""
66
+ if value is None:
67
+ return value
68
+
69
+ if value not in set(['reviewed', 'unreviewed']):
70
+ raise ValueError("must be one of enum values ('reviewed', 'unreviewed')")
71
+ return value
72
+
73
+ @field_validator('source')
74
+ def source_validate_enum(cls, value):
75
+ """Validates the enum"""
76
+ if value is None:
77
+ return value
78
+
79
+ if value not in set(['api', 'csv', 'manual', 'merge', 'plaid', 'recurring', 'rule', 'split', 'user']):
80
+ raise ValueError("must be one of enum values ('api', 'csv', 'manual', 'merge', 'plaid', 'recurring', 'rule', 'split', 'user')")
81
+ return value
82
+
83
+ model_config = ConfigDict(
84
+ populate_by_name=True,
85
+ validate_assignment=True,
86
+ protected_namespaces=(),
87
+ )
88
+
89
+
90
+ def to_str(self) -> str:
91
+ """Returns the string representation of the model using alias"""
92
+ return pprint.pformat(self.model_dump(by_alias=True))
93
+
94
+ def to_json(self) -> str:
95
+ """Returns the JSON representation of the model using alias"""
96
+ # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
97
+ return json.dumps(self.to_dict())
98
+
99
+ @classmethod
100
+ def from_json(cls, json_str: str) -> Optional[Self]:
101
+ """Create an instance of UpdateTransactionsRequestTransactionsInner from a JSON string"""
102
+ return cls.from_dict(json.loads(json_str))
103
+
104
+ def to_dict(self) -> Dict[str, Any]:
105
+ """Return the dictionary representation of the model using alias.
106
+
107
+ This has the following differences from calling pydantic's
108
+ `self.model_dump(by_alias=True)`:
109
+
110
+ * `None` is only added to the output dict for nullable fields that
111
+ were set at model initialization. Other fields with value `None`
112
+ are ignored.
113
+ """
114
+ excluded_fields: Set[str] = set([
115
+ ])
116
+
117
+ _dict = self.model_dump(
118
+ by_alias=True,
119
+ exclude=excluded_fields,
120
+ exclude_none=True,
121
+ )
122
+ # override the default output from pydantic by calling `to_dict()` of amount
123
+ if self.amount:
124
+ _dict['amount'] = self.amount.to_dict()
125
+ # override the default output from pydantic by calling `to_dict()` of each item in children (list)
126
+ _items = []
127
+ if self.children:
128
+ for _item_children in self.children:
129
+ if _item_children:
130
+ _items.append(_item_children.to_dict())
131
+ _dict['children'] = _items
132
+ # set to None if recurring_id (nullable) is None
133
+ # and model_fields_set contains the field
134
+ if self.recurring_id is None and "recurring_id" in self.model_fields_set:
135
+ _dict['recurring_id'] = None
136
+
137
+ # set to None if category_id (nullable) is None
138
+ # and model_fields_set contains the field
139
+ if self.category_id is None and "category_id" in self.model_fields_set:
140
+ _dict['category_id'] = None
141
+
142
+ # set to None if notes (nullable) is None
143
+ # and model_fields_set contains the field
144
+ if self.notes is None and "notes" in self.model_fields_set:
145
+ _dict['notes'] = None
146
+
147
+ # set to None if manual_account_id (nullable) is None
148
+ # and model_fields_set contains the field
149
+ if self.manual_account_id is None and "manual_account_id" in self.model_fields_set:
150
+ _dict['manual_account_id'] = None
151
+
152
+ # set to None if plaid_account_id (nullable) is None
153
+ # and model_fields_set contains the field
154
+ if self.plaid_account_id is None and "plaid_account_id" in self.model_fields_set:
155
+ _dict['plaid_account_id'] = None
156
+
157
+ # set to None if external_id (nullable) is None
158
+ # and model_fields_set contains the field
159
+ if self.external_id is None and "external_id" in self.model_fields_set:
160
+ _dict['external_id'] = None
161
+
162
+ # set to None if custom_metadata (nullable) is None
163
+ # and model_fields_set contains the field
164
+ if self.custom_metadata is None and "custom_metadata" in self.model_fields_set:
165
+ _dict['custom_metadata'] = None
166
+
167
+ # set to None if plaid_metadata (nullable) is None
168
+ # and model_fields_set contains the field
169
+ if self.plaid_metadata is None and "plaid_metadata" in self.model_fields_set:
170
+ _dict['plaid_metadata'] = None
171
+
172
+ # set to None if split_parent_id (nullable) is None
173
+ # and model_fields_set contains the field
174
+ if self.split_parent_id is None and "split_parent_id" in self.model_fields_set:
175
+ _dict['split_parent_id'] = None
176
+
177
+ # set to None if group_parent_id (nullable) is None
178
+ # and model_fields_set contains the field
179
+ if self.group_parent_id is None and "group_parent_id" in self.model_fields_set:
180
+ _dict['group_parent_id'] = None
181
+
182
+ # set to None if source (nullable) is None
183
+ # and model_fields_set contains the field
184
+ if self.source is None and "source" in self.model_fields_set:
185
+ _dict['source'] = None
186
+
187
+ return _dict
188
+
189
+ @classmethod
190
+ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
191
+ """Create an instance of UpdateTransactionsRequestTransactionsInner from a dict"""
192
+ if obj is None:
193
+ return None
194
+
195
+ if not isinstance(obj, dict):
196
+ return cls.model_validate(obj)
197
+
198
+ _obj = cls.model_validate({
199
+ "id": obj.get("id"),
200
+ "date": obj.get("date"),
201
+ "amount": UpdateTransactionObjectAmount.from_dict(obj["amount"]) if obj.get("amount") is not None else None,
202
+ "currency": obj.get("currency"),
203
+ "recurring_id": obj.get("recurring_id"),
204
+ "payee": obj.get("payee"),
205
+ "category_id": obj.get("category_id"),
206
+ "notes": obj.get("notes"),
207
+ "manual_account_id": obj.get("manual_account_id"),
208
+ "plaid_account_id": obj.get("plaid_account_id"),
209
+ "tag_ids": obj.get("tag_ids"),
210
+ "additional_tag_ids": obj.get("additional_tag_ids"),
211
+ "external_id": obj.get("external_id"),
212
+ "custom_metadata": obj.get("custom_metadata"),
213
+ "status": obj.get("status"),
214
+ "to_base": obj.get("to_base"),
215
+ "is_pending": obj.get("is_pending"),
216
+ "plaid_metadata": obj.get("plaid_metadata"),
217
+ "created_at": obj.get("created_at"),
218
+ "updated_at": obj.get("updated_at"),
219
+ "is_split_parent": obj.get("is_split_parent"),
220
+ "children": [ChildTransactionObject.from_dict(_item) for _item in obj["children"]] if obj.get("children") is not None else None,
221
+ "split_parent_id": obj.get("split_parent_id"),
222
+ "is_group_parent": obj.get("is_group_parent"),
223
+ "group_parent_id": obj.get("group_parent_id"),
224
+ "source": obj.get("source")
225
+ })
226
+ return _obj
227
+
228
+
@@ -0,0 +1,106 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ Lunch Money API - v2
5
+
6
+ Welcome to the Lunch Money v2 API. A working version of this API is now available through these docs, or directly at: `https://api.lunchmoney.dev/v2` <span class=\"red-text\"><strong>This is in alpha launch of a major API update. It is still subject to change during this alpha review period and bugs may still exist. Users are strongly encouraged to use the mock service or to create a test budget with example data as the first step to interacting with the v2 API.</strong></span> See the [Getting Started Guide](https://alpha.lunchmoney.dev/v2/getting-started) for more information on using a test budget.<br<br> If you are new to the v2 API, you may wish to review the [v2 API Overview of Changes](https://alpha.lunchmoney.dev/v2/changelog). ### Static Mock Server You may also use these docs to explore the API using a static mock server endpoint.<p> This enables users to become familiar with the API without having to create an access token, and eliminates the possibility of modifying real data. <p> To access this endpoint select the second endpoint in the the \"Server\" dropdown to the right. When selected you should see \"Static Mock v2 Lunch Money API Server\".<br> When using this server, set your Bearer token to any string with 11 or more characters. ### Migrating from V1 The v2 API is NOT backwards compatible with the v1 API. Developers are encouraged to review the [Migration Guide](https://alpha.lunchmoney.dev/v2/migration-guide) to understand the changes and plan their migration. ### Acknowledgments If you have been providing feedback on the API during our iterative design process, **THANK YOU**. We are happy to provide the opportunity to finally interact with the working API that was built based on your feedback. ### Useful links: - [Getting Started](https://alpha.lunchmoney.dev/v2/getting-started) - [v2 API Changelog](https://alpha.lunchmoney.dev/v2/changelog) - [Migration Guide](https://alpha.lunchmoney.dev/v2/migration-guide) - [Rate Limits](https://alpha.lunchmoney.dev/v2/rate-limits) - [Current v1 Lunch Money API Documentation](https://lunchmoney.dev) - [Awesome Lunch Money Projects](https://github.com/lunch-money/awesome-lunchmoney?tab=readme-ov-file)
7
+
8
+ The version of the OpenAPI document: 2.8.4
9
+ Contact: devsupport@lunchmoney.app
10
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
11
+
12
+ Do not edit the class manually.
13
+ """ # noqa: E501
14
+
15
+
16
+ from __future__ import annotations
17
+ import pprint
18
+ import re # noqa: F401
19
+ import json
20
+
21
+ from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr
22
+ from typing import Any, ClassVar, Dict, List, Optional
23
+ from lunchmoney.models.currency_enum import CurrencyEnum
24
+ from typing import Optional, Set
25
+ from typing_extensions import Self
26
+
27
+ class UserObject(BaseModel):
28
+ """
29
+ UserObject
30
+ """ # noqa: E501
31
+ name: StrictStr = Field(description="User's name")
32
+ email: StrictStr = Field(description="User's email")
33
+ id: StrictInt = Field(description="Unique identifier for user")
34
+ account_id: StrictInt = Field(description="Unique identifier for the associated budgeting account")
35
+ budget_name: StrictStr = Field(description="Name of the associated budgeting account")
36
+ primary_currency: CurrencyEnum = Field(description="Primary currency from user's settings")
37
+ api_key_label: Optional[StrictStr] = Field(description="User-defined label of the developer API key used. Returns null if nothing has been set.")
38
+ __properties: ClassVar[List[str]] = ["name", "email", "id", "account_id", "budget_name", "primary_currency", "api_key_label"]
39
+
40
+ model_config = ConfigDict(
41
+ populate_by_name=True,
42
+ validate_assignment=True,
43
+ protected_namespaces=(),
44
+ )
45
+
46
+
47
+ def to_str(self) -> str:
48
+ """Returns the string representation of the model using alias"""
49
+ return pprint.pformat(self.model_dump(by_alias=True))
50
+
51
+ def to_json(self) -> str:
52
+ """Returns the JSON representation of the model using alias"""
53
+ # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
54
+ return json.dumps(self.to_dict())
55
+
56
+ @classmethod
57
+ def from_json(cls, json_str: str) -> Optional[Self]:
58
+ """Create an instance of UserObject from a JSON string"""
59
+ return cls.from_dict(json.loads(json_str))
60
+
61
+ def to_dict(self) -> Dict[str, Any]:
62
+ """Return the dictionary representation of the model using alias.
63
+
64
+ This has the following differences from calling pydantic's
65
+ `self.model_dump(by_alias=True)`:
66
+
67
+ * `None` is only added to the output dict for nullable fields that
68
+ were set at model initialization. Other fields with value `None`
69
+ are ignored.
70
+ """
71
+ excluded_fields: Set[str] = set([
72
+ ])
73
+
74
+ _dict = self.model_dump(
75
+ by_alias=True,
76
+ exclude=excluded_fields,
77
+ exclude_none=True,
78
+ )
79
+ # set to None if api_key_label (nullable) is None
80
+ # and model_fields_set contains the field
81
+ if self.api_key_label is None and "api_key_label" in self.model_fields_set:
82
+ _dict['api_key_label'] = None
83
+
84
+ return _dict
85
+
86
+ @classmethod
87
+ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
88
+ """Create an instance of UserObject from a dict"""
89
+ if obj is None:
90
+ return None
91
+
92
+ if not isinstance(obj, dict):
93
+ return cls.model_validate(obj)
94
+
95
+ _obj = cls.model_validate({
96
+ "name": obj.get("name"),
97
+ "email": obj.get("email"),
98
+ "id": obj.get("id"),
99
+ "account_id": obj.get("account_id"),
100
+ "budget_name": obj.get("budget_name"),
101
+ "primary_currency": obj.get("primary_currency"),
102
+ "api_key_label": obj.get("api_key_label")
103
+ })
104
+ return _obj
105
+
106
+
lunchmoney/py.typed ADDED
File without changes
lunchmoney/rest.py ADDED
@@ -0,0 +1,259 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ Lunch Money API - v2
5
+
6
+ Welcome to the Lunch Money v2 API. A working version of this API is now available through these docs, or directly at: `https://api.lunchmoney.dev/v2` <span class=\"red-text\"><strong>This is in alpha launch of a major API update. It is still subject to change during this alpha review period and bugs may still exist. Users are strongly encouraged to use the mock service or to create a test budget with example data as the first step to interacting with the v2 API.</strong></span> See the [Getting Started Guide](https://alpha.lunchmoney.dev/v2/getting-started) for more information on using a test budget.<br<br> If you are new to the v2 API, you may wish to review the [v2 API Overview of Changes](https://alpha.lunchmoney.dev/v2/changelog). ### Static Mock Server You may also use these docs to explore the API using a static mock server endpoint.<p> This enables users to become familiar with the API without having to create an access token, and eliminates the possibility of modifying real data. <p> To access this endpoint select the second endpoint in the the \"Server\" dropdown to the right. When selected you should see \"Static Mock v2 Lunch Money API Server\".<br> When using this server, set your Bearer token to any string with 11 or more characters. ### Migrating from V1 The v2 API is NOT backwards compatible with the v1 API. Developers are encouraged to review the [Migration Guide](https://alpha.lunchmoney.dev/v2/migration-guide) to understand the changes and plan their migration. ### Acknowledgments If you have been providing feedback on the API during our iterative design process, **THANK YOU**. We are happy to provide the opportunity to finally interact with the working API that was built based on your feedback. ### Useful links: - [Getting Started](https://alpha.lunchmoney.dev/v2/getting-started) - [v2 API Changelog](https://alpha.lunchmoney.dev/v2/changelog) - [Migration Guide](https://alpha.lunchmoney.dev/v2/migration-guide) - [Rate Limits](https://alpha.lunchmoney.dev/v2/rate-limits) - [Current v1 Lunch Money API Documentation](https://lunchmoney.dev) - [Awesome Lunch Money Projects](https://github.com/lunch-money/awesome-lunchmoney?tab=readme-ov-file)
7
+
8
+ The version of the OpenAPI document: 2.8.4
9
+ Contact: devsupport@lunchmoney.app
10
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
11
+
12
+ Do not edit the class manually.
13
+ """ # noqa: E501
14
+
15
+
16
+ import io
17
+ import json
18
+ import re
19
+ import ssl
20
+
21
+ import urllib3
22
+
23
+ from lunchmoney.exceptions import ApiException, ApiValueError
24
+
25
+ SUPPORTED_SOCKS_PROXIES = {"socks5", "socks5h", "socks4", "socks4a"}
26
+ RESTResponseType = urllib3.HTTPResponse
27
+
28
+
29
+ def is_socks_proxy_url(url):
30
+ if url is None:
31
+ return False
32
+ split_section = url.split("://")
33
+ if len(split_section) < 2:
34
+ return False
35
+ else:
36
+ return split_section[0].lower() in SUPPORTED_SOCKS_PROXIES
37
+
38
+
39
+ class RESTResponse(io.IOBase):
40
+
41
+ def __init__(self, resp) -> None:
42
+ self.response = resp
43
+ self.status = resp.status
44
+ self.reason = resp.reason
45
+ self.data = None
46
+
47
+ def read(self):
48
+ if self.data is None:
49
+ self.data = self.response.data
50
+ return self.data
51
+
52
+ def getheaders(self):
53
+ """Returns a dictionary of the response headers."""
54
+ return self.response.headers
55
+
56
+ def getheader(self, name, default=None):
57
+ """Returns a given response header."""
58
+ return self.response.headers.get(name, default)
59
+
60
+
61
+ class RESTClientObject:
62
+
63
+ def __init__(self, configuration) -> None:
64
+ # urllib3.PoolManager will pass all kw parameters to connectionpool
65
+ # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/poolmanager.py#L75 # noqa: E501
66
+ # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/connectionpool.py#L680 # noqa: E501
67
+ # Custom SSL certificates and client certificates: http://urllib3.readthedocs.io/en/latest/advanced-usage.html # noqa: E501
68
+
69
+ # cert_reqs
70
+ if configuration.verify_ssl:
71
+ cert_reqs = ssl.CERT_REQUIRED
72
+ else:
73
+ cert_reqs = ssl.CERT_NONE
74
+
75
+ pool_args = {
76
+ "cert_reqs": cert_reqs,
77
+ "ca_certs": configuration.ssl_ca_cert,
78
+ "cert_file": configuration.cert_file,
79
+ "key_file": configuration.key_file,
80
+ "ca_cert_data": configuration.ca_cert_data,
81
+ }
82
+ if configuration.assert_hostname is not None:
83
+ pool_args['assert_hostname'] = (
84
+ configuration.assert_hostname
85
+ )
86
+
87
+ if configuration.retries is not None:
88
+ pool_args['retries'] = configuration.retries
89
+
90
+ if configuration.tls_server_name:
91
+ pool_args['server_hostname'] = configuration.tls_server_name
92
+
93
+
94
+ if configuration.socket_options is not None:
95
+ pool_args['socket_options'] = configuration.socket_options
96
+
97
+ if configuration.connection_pool_maxsize is not None:
98
+ pool_args['maxsize'] = configuration.connection_pool_maxsize
99
+
100
+ # https pool manager
101
+ self.pool_manager: urllib3.PoolManager
102
+
103
+ if configuration.proxy:
104
+ if is_socks_proxy_url(configuration.proxy):
105
+ from urllib3.contrib.socks import SOCKSProxyManager
106
+ pool_args["proxy_url"] = configuration.proxy
107
+ pool_args["headers"] = configuration.proxy_headers
108
+ self.pool_manager = SOCKSProxyManager(**pool_args)
109
+ else:
110
+ pool_args["proxy_url"] = configuration.proxy
111
+ pool_args["proxy_headers"] = configuration.proxy_headers
112
+ self.pool_manager = urllib3.ProxyManager(**pool_args)
113
+ else:
114
+ self.pool_manager = urllib3.PoolManager(**pool_args)
115
+
116
+ def request(
117
+ self,
118
+ method,
119
+ url,
120
+ headers=None,
121
+ body=None,
122
+ post_params=None,
123
+ _request_timeout=None
124
+ ):
125
+ """Perform requests.
126
+
127
+ :param method: http request method
128
+ :param url: http request url
129
+ :param headers: http request headers
130
+ :param body: request json body, for `application/json`
131
+ :param post_params: request post parameters,
132
+ `application/x-www-form-urlencoded`
133
+ and `multipart/form-data`
134
+ :param _request_timeout: timeout setting for this request. If one
135
+ number provided, it will be total request
136
+ timeout. It can also be a pair (tuple) of
137
+ (connection, read) timeouts.
138
+ """
139
+ method = method.upper()
140
+ assert method in [
141
+ 'GET',
142
+ 'HEAD',
143
+ 'DELETE',
144
+ 'POST',
145
+ 'PUT',
146
+ 'PATCH',
147
+ 'OPTIONS'
148
+ ]
149
+
150
+ if post_params and body:
151
+ raise ApiValueError(
152
+ "body parameter cannot be used with post_params parameter."
153
+ )
154
+
155
+ post_params = post_params or {}
156
+ headers = headers or {}
157
+
158
+ timeout = None
159
+ if _request_timeout:
160
+ if isinstance(_request_timeout, (int, float)):
161
+ timeout = urllib3.Timeout(total=_request_timeout)
162
+ elif (
163
+ isinstance(_request_timeout, tuple)
164
+ and len(_request_timeout) == 2
165
+ ):
166
+ timeout = urllib3.Timeout(
167
+ connect=_request_timeout[0],
168
+ read=_request_timeout[1]
169
+ )
170
+
171
+ try:
172
+ # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`
173
+ if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']:
174
+
175
+ # no content type provided or payload is json
176
+ content_type = headers.get('Content-Type')
177
+ if (
178
+ not content_type
179
+ or re.search('json', content_type, re.IGNORECASE)
180
+ ):
181
+ request_body = None
182
+ if body is not None:
183
+ request_body = json.dumps(body)
184
+ r = self.pool_manager.request(
185
+ method,
186
+ url,
187
+ body=request_body,
188
+ timeout=timeout,
189
+ headers=headers,
190
+ preload_content=False
191
+ )
192
+ elif content_type == 'application/x-www-form-urlencoded':
193
+ r = self.pool_manager.request(
194
+ method,
195
+ url,
196
+ fields=post_params,
197
+ encode_multipart=False,
198
+ timeout=timeout,
199
+ headers=headers,
200
+ preload_content=False
201
+ )
202
+ elif content_type == 'multipart/form-data':
203
+ # must del headers['Content-Type'], or the correct
204
+ # Content-Type which generated by urllib3 will be
205
+ # overwritten.
206
+ del headers['Content-Type']
207
+ # Ensures that dict objects are serialized
208
+ post_params = [(a, json.dumps(b)) if isinstance(b, dict) else (a,b) for a, b in post_params]
209
+ r = self.pool_manager.request(
210
+ method,
211
+ url,
212
+ fields=post_params,
213
+ encode_multipart=True,
214
+ timeout=timeout,
215
+ headers=headers,
216
+ preload_content=False
217
+ )
218
+ # Pass a `string` parameter directly in the body to support
219
+ # other content types than JSON when `body` argument is
220
+ # provided in serialized form.
221
+ elif isinstance(body, str) or isinstance(body, bytes):
222
+ r = self.pool_manager.request(
223
+ method,
224
+ url,
225
+ body=body,
226
+ timeout=timeout,
227
+ headers=headers,
228
+ preload_content=False
229
+ )
230
+ elif headers['Content-Type'].startswith('text/') and isinstance(body, bool):
231
+ request_body = "true" if body else "false"
232
+ r = self.pool_manager.request(
233
+ method,
234
+ url,
235
+ body=request_body,
236
+ preload_content=False,
237
+ timeout=timeout,
238
+ headers=headers)
239
+ else:
240
+ # Cannot generate the request from given parameters
241
+ msg = """Cannot prepare a request message for provided
242
+ arguments. Please check that your arguments match
243
+ declared content type."""
244
+ raise ApiException(status=0, reason=msg)
245
+ # For `GET`, `HEAD`
246
+ else:
247
+ r = self.pool_manager.request(
248
+ method,
249
+ url,
250
+ fields={},
251
+ timeout=timeout,
252
+ headers=headers,
253
+ preload_content=False
254
+ )
255
+ except urllib3.exceptions.SSLError as e:
256
+ msg = "\n".join([type(e).__name__, str(e)])
257
+ raise ApiException(status=0, reason=msg)
258
+
259
+ return RESTResponse(r)