spoolman 0.1.0__tar.gz

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.
spoolman-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Klaas Schoute
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,218 @@
1
+ Metadata-Version: 2.1
2
+ Name: spoolman
3
+ Version: 0.1.0
4
+ Summary: Asynchronous Python client for Spoolman API
5
+ Home-page: https://github.com/klaasnicolaas/python-spoolman
6
+ License: MIT
7
+ Keywords: spoolman,api,async,client
8
+ Author: Klaas Schoute
9
+ Author-email: hello@student-techlife.com
10
+ Maintainer: Klaas Schoute
11
+ Maintainer-email: hello@student-techlife.com
12
+ Requires-Python: >=3.11,<4.0
13
+ Classifier: Framework :: AsyncIO
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Natural Language :: English
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Dist: aiohttp (>=3.0.0)
23
+ Requires-Dist: mashumaro (>=3.15,<4.0)
24
+ Requires-Dist: yarl (>=1.6.0)
25
+ Project-URL: Bug Tracker, https://github.com/klaasnicolaas/python-spoolman/issues
26
+ Project-URL: Changelog, https://github.com/klaasnicolaas/python-spoolman/releases
27
+ Project-URL: Documentation, https://github.com/klaasnicolaas/python-spoolman
28
+ Project-URL: Repository, https://github.com/klaasnicolaas/python-spoolman
29
+ Description-Content-Type: text/markdown
30
+
31
+ <!-- Banner -->
32
+ ![alt Banner of the Spoolman package](https://raw.githubusercontent.com/klaasnicolaas/python-spoolman/main/assets/header_spoolman-min.png)
33
+
34
+ <!-- PROJECT SHIELDS -->
35
+ [![GitHub Release][releases-shield]][releases]
36
+ [![Python Versions][python-versions-shield]][pypi]
37
+ ![Project Stage][project-stage-shield]
38
+ ![Project Maintenance][maintenance-shield]
39
+ [![License][license-shield]](LICENSE)
40
+
41
+ [![GitHub Activity][commits-shield]][commits-url]
42
+ [![PyPi Downloads][downloads-shield]][downloads-url]
43
+ [![GitHub Last Commit][last-commit-shield]][commits-url]
44
+ [![Open in Dev Containers][devcontainer-shield]][devcontainer]
45
+
46
+ [![Build Status][build-shield]][build-url]
47
+ [![Typing Status][typing-shield]][typing-url]
48
+ [![Code Coverage][codecov-shield]][codecov-url]
49
+
50
+
51
+ Asynchronous Python client for [Spoolman][spoolman].
52
+
53
+ ## About
54
+
55
+ Spoolman is a self-hosted platform for managing 3D printer filament spools. It integrates with popular 3D printing software to track spool weights in real time, providing instant insights into filament usage.
56
+
57
+ ## Installation
58
+
59
+ ```bash
60
+ pip install spoolman
61
+ ```
62
+
63
+ ## Data
64
+
65
+ - Application info and health
66
+ - Filaments
67
+ - Spools
68
+ - Vendors
69
+
70
+ ### Example
71
+
72
+ ```python
73
+ import asyncio
74
+
75
+ from spoolman import Spoolman
76
+
77
+
78
+ async def main() -> None:
79
+ """Show example on using this package."""
80
+ async with Spoolman(host="IP_ADDRESS") as client:
81
+ # Get all filaments
82
+ filaments = await client.get_filaments()
83
+ print(filaments)
84
+
85
+
86
+ if __name__ == "__main__":
87
+ asyncio.run(main())
88
+ ```
89
+
90
+ More examples can be found in the [examples folder](./examples/).
91
+
92
+ ## Class Parameters
93
+
94
+ | Parameter | value Type | Description |
95
+ | :-------- | :--------- | :---------------------------------------------------------------- |
96
+ | `host` | `str` | The IP address of your Spoolman instance. |
97
+ | `port` | `int` | The port of your Spoolman instance (optional). Default is `7912`. |
98
+
99
+ ## Contributing
100
+
101
+ This is an active open-source project. We are always open to people who want to
102
+ use the code or contribute to it.
103
+
104
+ We've set up a separate document for our
105
+ [contribution guidelines](CONTRIBUTING.md).
106
+
107
+ Thank you for being involved! :heart_eyes:
108
+
109
+ ## Setting up development environment
110
+
111
+ The simplest way to begin is by utilizing the [Dev Container][devcontainer]
112
+ feature of Visual Studio Code or by opening a CodeSpace directly on GitHub.
113
+ By clicking the button below you immediately start a Dev Container in Visual Studio Code.
114
+
115
+ [![Open in Dev Containers][devcontainer-shield]][devcontainer]
116
+
117
+ This Python project relies on [Poetry][poetry] as its dependency manager,
118
+ providing comprehensive management and control over project dependencies.
119
+
120
+ You need at least:
121
+
122
+ - Python 3.11+
123
+ - [Poetry][poetry-install]
124
+
125
+ ### Installation
126
+
127
+ Install all packages, including all development requirements:
128
+
129
+ ```bash
130
+ poetry install
131
+ ```
132
+
133
+ _Poetry creates by default an virtual environment where it installs all
134
+ necessary pip packages_.
135
+
136
+ ### Pre-commit
137
+
138
+ This repository uses the [pre-commit][pre-commit] framework, all changes
139
+ are linted and tested with each commit. To setup the pre-commit check, run:
140
+
141
+ ```bash
142
+ poetry run pre-commit install
143
+ ```
144
+
145
+ And to run all checks and tests manually, use the following command:
146
+
147
+ ```bash
148
+ poetry run pre-commit run --all-files
149
+ ```
150
+
151
+ ### Testing
152
+
153
+ It uses [pytest](https://docs.pytest.org/en/stable/) as the test framework. To run the tests:
154
+
155
+ ```bash
156
+ poetry run pytest
157
+ ```
158
+
159
+ To update the [syrupy](https://github.com/tophat/syrupy) snapshot tests:
160
+
161
+ ```bash
162
+ poetry run pytest --snapshot-update
163
+ ```
164
+
165
+ ## License
166
+
167
+ MIT License
168
+
169
+ Copyright (c) 2024 Klaas Schoute
170
+
171
+ Permission is hereby granted, free of charge, to any person obtaining a copy
172
+ of this software and associated documentation files (the "Software"), to deal
173
+ in the Software without restriction, including without limitation the rights
174
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
175
+ copies of the Software, and to permit persons to whom the Software is
176
+ furnished to do so, subject to the following conditions:
177
+
178
+ The above copyright notice and this permission notice shall be included in all
179
+ copies or substantial portions of the Software.
180
+
181
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
182
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
183
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
184
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
185
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
186
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
187
+ SOFTWARE.
188
+
189
+
190
+ <!-- LINKS FROM PLATFORM -->
191
+ [spoolman]: https://github.com/Donkie/Spoolman
192
+
193
+ <!-- MARKDOWN LINKS & IMAGES -->
194
+ [build-shield]: https://github.com/klaasnicolaas/python-spoolman/actions/workflows/tests.yaml/badge.svg
195
+ [build-url]: https://github.com/klaasnicolaas/python-spoolman/actions/workflows/tests.yaml
196
+ [codecov-shield]: https://codecov.io/gh/klaasnicolaas/python-spoolman/branch/main/graph/badge.svg?token=C92VQ5QJ21
197
+ [codecov-url]: https://codecov.io/gh/klaasnicolaas/python-spoolman
198
+ [commits-shield]: https://img.shields.io/github/commit-activity/y/klaasnicolaas/python-spoolman.svg
199
+ [commits-url]: https://github.com/klaasnicolaas/python-spoolman/commits/main
200
+ [devcontainer-shield]: https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode
201
+ [devcontainer]: https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/klaasnicolaas/python-spoolman
202
+ [downloads-shield]: https://img.shields.io/pypi/dm/spoolman
203
+ [downloads-url]: https://pypistats.org/packages/spoolman
204
+ [last-commit-shield]: https://img.shields.io/github/last-commit/klaasnicolaas/python-spoolman.svg
205
+ [license-shield]: https://img.shields.io/github/license/klaasnicolaas/python-spoolman.svg
206
+ [maintenance-shield]: https://img.shields.io/maintenance/yes/2024.svg
207
+ [project-stage-shield]: https://img.shields.io/badge/project%20stage-experimental-yellow.svg
208
+ [pypi]: https://pypi.org/project/spoolman/
209
+ [python-versions-shield]: https://img.shields.io/pypi/pyversions/spoolman
210
+ [releases-shield]: https://img.shields.io/github/release/klaasnicolaas/python-spoolman.svg
211
+ [releases]: https://github.com/klaasnicolaas/python-spoolman/releases
212
+ [typing-shield]: https://github.com/klaasnicolaas/python-spoolman/actions/workflows/typing.yaml/badge.svg
213
+ [typing-url]: https://github.com/klaasnicolaas/python-spoolman/actions/workflows/typing.yaml
214
+
215
+ [poetry-install]: https://python-poetry.org/docs/#installation
216
+ [poetry]: https://python-poetry.org
217
+ [pre-commit]: https://pre-commit.com
218
+
@@ -0,0 +1,187 @@
1
+ <!-- Banner -->
2
+ ![alt Banner of the Spoolman package](https://raw.githubusercontent.com/klaasnicolaas/python-spoolman/main/assets/header_spoolman-min.png)
3
+
4
+ <!-- PROJECT SHIELDS -->
5
+ [![GitHub Release][releases-shield]][releases]
6
+ [![Python Versions][python-versions-shield]][pypi]
7
+ ![Project Stage][project-stage-shield]
8
+ ![Project Maintenance][maintenance-shield]
9
+ [![License][license-shield]](LICENSE)
10
+
11
+ [![GitHub Activity][commits-shield]][commits-url]
12
+ [![PyPi Downloads][downloads-shield]][downloads-url]
13
+ [![GitHub Last Commit][last-commit-shield]][commits-url]
14
+ [![Open in Dev Containers][devcontainer-shield]][devcontainer]
15
+
16
+ [![Build Status][build-shield]][build-url]
17
+ [![Typing Status][typing-shield]][typing-url]
18
+ [![Code Coverage][codecov-shield]][codecov-url]
19
+
20
+
21
+ Asynchronous Python client for [Spoolman][spoolman].
22
+
23
+ ## About
24
+
25
+ Spoolman is a self-hosted platform for managing 3D printer filament spools. It integrates with popular 3D printing software to track spool weights in real time, providing instant insights into filament usage.
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ pip install spoolman
31
+ ```
32
+
33
+ ## Data
34
+
35
+ - Application info and health
36
+ - Filaments
37
+ - Spools
38
+ - Vendors
39
+
40
+ ### Example
41
+
42
+ ```python
43
+ import asyncio
44
+
45
+ from spoolman import Spoolman
46
+
47
+
48
+ async def main() -> None:
49
+ """Show example on using this package."""
50
+ async with Spoolman(host="IP_ADDRESS") as client:
51
+ # Get all filaments
52
+ filaments = await client.get_filaments()
53
+ print(filaments)
54
+
55
+
56
+ if __name__ == "__main__":
57
+ asyncio.run(main())
58
+ ```
59
+
60
+ More examples can be found in the [examples folder](./examples/).
61
+
62
+ ## Class Parameters
63
+
64
+ | Parameter | value Type | Description |
65
+ | :-------- | :--------- | :---------------------------------------------------------------- |
66
+ | `host` | `str` | The IP address of your Spoolman instance. |
67
+ | `port` | `int` | The port of your Spoolman instance (optional). Default is `7912`. |
68
+
69
+ ## Contributing
70
+
71
+ This is an active open-source project. We are always open to people who want to
72
+ use the code or contribute to it.
73
+
74
+ We've set up a separate document for our
75
+ [contribution guidelines](CONTRIBUTING.md).
76
+
77
+ Thank you for being involved! :heart_eyes:
78
+
79
+ ## Setting up development environment
80
+
81
+ The simplest way to begin is by utilizing the [Dev Container][devcontainer]
82
+ feature of Visual Studio Code or by opening a CodeSpace directly on GitHub.
83
+ By clicking the button below you immediately start a Dev Container in Visual Studio Code.
84
+
85
+ [![Open in Dev Containers][devcontainer-shield]][devcontainer]
86
+
87
+ This Python project relies on [Poetry][poetry] as its dependency manager,
88
+ providing comprehensive management and control over project dependencies.
89
+
90
+ You need at least:
91
+
92
+ - Python 3.11+
93
+ - [Poetry][poetry-install]
94
+
95
+ ### Installation
96
+
97
+ Install all packages, including all development requirements:
98
+
99
+ ```bash
100
+ poetry install
101
+ ```
102
+
103
+ _Poetry creates by default an virtual environment where it installs all
104
+ necessary pip packages_.
105
+
106
+ ### Pre-commit
107
+
108
+ This repository uses the [pre-commit][pre-commit] framework, all changes
109
+ are linted and tested with each commit. To setup the pre-commit check, run:
110
+
111
+ ```bash
112
+ poetry run pre-commit install
113
+ ```
114
+
115
+ And to run all checks and tests manually, use the following command:
116
+
117
+ ```bash
118
+ poetry run pre-commit run --all-files
119
+ ```
120
+
121
+ ### Testing
122
+
123
+ It uses [pytest](https://docs.pytest.org/en/stable/) as the test framework. To run the tests:
124
+
125
+ ```bash
126
+ poetry run pytest
127
+ ```
128
+
129
+ To update the [syrupy](https://github.com/tophat/syrupy) snapshot tests:
130
+
131
+ ```bash
132
+ poetry run pytest --snapshot-update
133
+ ```
134
+
135
+ ## License
136
+
137
+ MIT License
138
+
139
+ Copyright (c) 2024 Klaas Schoute
140
+
141
+ Permission is hereby granted, free of charge, to any person obtaining a copy
142
+ of this software and associated documentation files (the "Software"), to deal
143
+ in the Software without restriction, including without limitation the rights
144
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
145
+ copies of the Software, and to permit persons to whom the Software is
146
+ furnished to do so, subject to the following conditions:
147
+
148
+ The above copyright notice and this permission notice shall be included in all
149
+ copies or substantial portions of the Software.
150
+
151
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
152
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
153
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
154
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
155
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
156
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
157
+ SOFTWARE.
158
+
159
+
160
+ <!-- LINKS FROM PLATFORM -->
161
+ [spoolman]: https://github.com/Donkie/Spoolman
162
+
163
+ <!-- MARKDOWN LINKS & IMAGES -->
164
+ [build-shield]: https://github.com/klaasnicolaas/python-spoolman/actions/workflows/tests.yaml/badge.svg
165
+ [build-url]: https://github.com/klaasnicolaas/python-spoolman/actions/workflows/tests.yaml
166
+ [codecov-shield]: https://codecov.io/gh/klaasnicolaas/python-spoolman/branch/main/graph/badge.svg?token=C92VQ5QJ21
167
+ [codecov-url]: https://codecov.io/gh/klaasnicolaas/python-spoolman
168
+ [commits-shield]: https://img.shields.io/github/commit-activity/y/klaasnicolaas/python-spoolman.svg
169
+ [commits-url]: https://github.com/klaasnicolaas/python-spoolman/commits/main
170
+ [devcontainer-shield]: https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode
171
+ [devcontainer]: https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/klaasnicolaas/python-spoolman
172
+ [downloads-shield]: https://img.shields.io/pypi/dm/spoolman
173
+ [downloads-url]: https://pypistats.org/packages/spoolman
174
+ [last-commit-shield]: https://img.shields.io/github/last-commit/klaasnicolaas/python-spoolman.svg
175
+ [license-shield]: https://img.shields.io/github/license/klaasnicolaas/python-spoolman.svg
176
+ [maintenance-shield]: https://img.shields.io/maintenance/yes/2024.svg
177
+ [project-stage-shield]: https://img.shields.io/badge/project%20stage-experimental-yellow.svg
178
+ [pypi]: https://pypi.org/project/spoolman/
179
+ [python-versions-shield]: https://img.shields.io/pypi/pyversions/spoolman
180
+ [releases-shield]: https://img.shields.io/github/release/klaasnicolaas/python-spoolman.svg
181
+ [releases]: https://github.com/klaasnicolaas/python-spoolman/releases
182
+ [typing-shield]: https://github.com/klaasnicolaas/python-spoolman/actions/workflows/typing.yaml/badge.svg
183
+ [typing-url]: https://github.com/klaasnicolaas/python-spoolman/actions/workflows/typing.yaml
184
+
185
+ [poetry-install]: https://python-poetry.org/docs/#installation
186
+ [poetry]: https://python-poetry.org
187
+ [pre-commit]: https://pre-commit.com
@@ -0,0 +1,149 @@
1
+ [tool.poetry]
2
+ name = "spoolman"
3
+ version = "0.1.0"
4
+ description = "Asynchronous Python client for Spoolman API"
5
+ authors = ["Klaas Schoute <hello@student-techlife.com>"]
6
+ maintainers = ["Klaas Schoute <hello@student-techlife.com>"]
7
+ license = "MIT"
8
+ readme = "README.md"
9
+ homepage = "https://github.com/klaasnicolaas/python-spoolman"
10
+ repository = "https://github.com/klaasnicolaas/python-spoolman"
11
+ documentation = "https://github.com/klaasnicolaas/python-spoolman"
12
+ keywords = ["spoolman", "api", "async", "client"]
13
+ classifiers = [
14
+ "Framework :: AsyncIO",
15
+ "Intended Audience :: Developers",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Natural Language :: English",
18
+ "Programming Language :: Python :: 3.11",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
21
+ "Programming Language :: Python :: 3",
22
+ "Topic :: Software Development :: Libraries :: Python Modules",
23
+ ]
24
+ packages = [
25
+ { include = "spoolman", from = "src"},
26
+ ]
27
+
28
+ [tool.poetry.dependencies]
29
+ aiohttp = ">=3.0.0"
30
+ python = "^3.11"
31
+ yarl = ">=1.6.0"
32
+ mashumaro = "^3.15"
33
+
34
+ [tool.poetry.urls]
35
+ "Bug Tracker" = "https://github.com/klaasnicolaas/python-spoolman/issues"
36
+ Changelog = "https://github.com/klaasnicolaas/python-spoolman/releases"
37
+
38
+ [tool.poetry.group.dev.dependencies]
39
+ aresponses = "3.0.0"
40
+ codespell = "2.3.0"
41
+ covdefaults = "2.3.0"
42
+ coverage = {version = "7.6.10", extras = ["toml"]}
43
+ mypy = "1.13.0"
44
+ pre-commit = "4.0.1"
45
+ pre-commit-hooks = "5.0.0"
46
+ pylint = "3.3.3"
47
+ pytest = "8.3.4"
48
+ pytest-asyncio = "0.24.0"
49
+ pytest-cov = "6.0.0"
50
+ ruff = "0.8.0"
51
+ syrupy = "4.8.0"
52
+ yamllint = "1.35.1"
53
+
54
+ [tool.coverage.run]
55
+ plugins = ["covdefaults"]
56
+ source = ["spoolman"]
57
+
58
+ [tool.coverage.report]
59
+ fail_under = 90
60
+ show_missing = true
61
+
62
+ [tool.mypy]
63
+ # Specify the target platform details in config, so your developers are
64
+ # free to run mypy on Windows, Linux, or macOS and get consistent
65
+ # results.
66
+ platform = "linux"
67
+ python_version = "3.11"
68
+
69
+ # flake8-mypy expects the two following for sensible formatting
70
+ show_column_numbers = true
71
+
72
+ # show error messages from unrelated files
73
+ follow_imports = "normal"
74
+
75
+ # suppress errors about unsatisfied imports
76
+ ignore_missing_imports = true
77
+
78
+ # be strict
79
+ check_untyped_defs = true
80
+ disallow_any_generics = true
81
+ disallow_incomplete_defs = true
82
+ disallow_subclassing_any = true
83
+ disallow_untyped_calls = true
84
+ disallow_untyped_decorators = true
85
+ disallow_untyped_defs = true
86
+ no_implicit_optional = true
87
+ no_implicit_reexport = true
88
+ strict_optional = true
89
+ warn_incomplete_stub = true
90
+ warn_no_return = true
91
+ warn_redundant_casts = true
92
+ warn_return_any = true
93
+ warn_unused_configs = true
94
+ warn_unused_ignores = true
95
+
96
+ [tool.pylint.MASTER]
97
+ ignore = ["tests"]
98
+
99
+ [tool.pylint.BASIC]
100
+ good-names = ["_", "ex", "fp", "i", "id", "j", "k", "on", "Run", "T"]
101
+
102
+ [tool.pylint."MESSAGES CONTROL"]
103
+ disable= [
104
+ "duplicate-code",
105
+ "format",
106
+ "unsubscriptable-object",
107
+ ]
108
+
109
+ [tool.pylint.SIMILARITIES]
110
+ ignore-imports = true
111
+
112
+ [tool.pylint.FORMAT]
113
+ max-line-length = 88
114
+
115
+ [tool.pylint.DESIGN]
116
+ max-attributes = 20
117
+
118
+ [tool.pytest.ini_options]
119
+ addopts = "--cov"
120
+ asyncio_mode = "auto"
121
+
122
+ [tool.ruff]
123
+ lint.select = ["ALL"]
124
+ lint.ignore = [
125
+ "ANN401", # Opinioated warning on disallowing dynamically typed expressions
126
+ "D203", # Conflicts with other rules
127
+ "D213", # Conflicts with other rules
128
+ "D417", # False positives in some occasions
129
+ "PLR2004", # Just annoying, not really useful
130
+ "SLOT000", # Has a bug with enums: https://github.com/astral-sh/ruff/issues/5748
131
+
132
+ # Conflicts with the Ruff formatter
133
+ "COM812",
134
+ "ISC001",
135
+ ]
136
+
137
+ [tool.ruff.lint.flake8-pytest-style]
138
+ mark-parentheses = false
139
+ fixture-parentheses = false
140
+
141
+ [tool.ruff.lint.isort]
142
+ known-first-party = ["spoolman"]
143
+
144
+ [tool.ruff.lint.mccabe]
145
+ max-complexity = 25
146
+
147
+ [build-system]
148
+ build-backend = "poetry.core.masonry.api"
149
+ requires = ["poetry-core>=1.0.0"]
@@ -0,0 +1,16 @@
1
+ """Asynchronous Python client for Spoolman."""
2
+
3
+ from .exceptions import SpoolmanConnectionError, SpoolmanError, SpoolmanResponseError
4
+ from .models import Filament, Info, Spool, Vendor
5
+ from .spoolman import Spoolman
6
+
7
+ __all__ = [
8
+ "Filament",
9
+ "Info",
10
+ "Spool",
11
+ "Spoolman",
12
+ "SpoolmanConnectionError",
13
+ "SpoolmanError",
14
+ "SpoolmanResponseError",
15
+ "Vendor",
16
+ ]
@@ -0,0 +1,17 @@
1
+ """Asynchronous Python client for Spoolman."""
2
+
3
+
4
+ class SpoolmanError(Exception):
5
+ """Base class for Spoolman exceptions."""
6
+
7
+
8
+ class SpoolmanConnectionError(SpoolmanError):
9
+ """Error raised when connection to the API fails."""
10
+
11
+
12
+ class SpoolmanResponseError(SpoolmanError):
13
+ """Error raised when the API returns a error."""
14
+
15
+ def __init__(self, data: dict[str, str], code: int) -> None:
16
+ """Initialize the exception."""
17
+ super().__init__(f'{data["message"]} (code: {code})')
@@ -0,0 +1,77 @@
1
+ """Asynchronous Python client for Spoolman."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from datetime import datetime # noqa: TC003
7
+
8
+ from mashumaro import DataClassDictMixin, field_options
9
+
10
+
11
+ @dataclass
12
+ class Info(DataClassDictMixin):
13
+ """Data class for the 'info' endpoint."""
14
+
15
+ version: str
16
+ debug_mode: bool
17
+ automatic_backups: bool
18
+ db_type: str
19
+ git_commit: str
20
+ build_date: datetime
21
+ data_dir: str
22
+ logs_dir: str
23
+ backups_dir: str
24
+
25
+
26
+ @dataclass
27
+ class Filament(DataClassDictMixin):
28
+ """Data class for filament data."""
29
+
30
+ id: int
31
+ name: str
32
+ color: str = field(metadata=field_options(alias="color_hex"))
33
+ vendor: Vendor
34
+ external_id: str
35
+ registered: datetime
36
+
37
+ material: str
38
+ density: float
39
+ diameter: float
40
+ weight: float
41
+ spool_weight: float
42
+ extruder_temp: int = field(metadata=field_options(alias="settings_extruder_temp"))
43
+ bed_temp: int = field(metadata=field_options(alias="settings_bed_temp"))
44
+
45
+
46
+ @dataclass
47
+ class Spool(DataClassDictMixin):
48
+ """Data class for spool data."""
49
+
50
+ id: int
51
+ filament: Filament
52
+
53
+ initial_weight: float
54
+ spool_weight: float
55
+ used_weight: float
56
+ used_length: float
57
+ remaining_weight: float
58
+ remaining_length: float
59
+
60
+ archived: bool
61
+ registered: datetime
62
+ first_used: datetime | None = field(
63
+ default=None, metadata=field_options(alias="first_used")
64
+ )
65
+ last_used: datetime | None = field(
66
+ default=None, metadata=field_options(alias="last_used")
67
+ )
68
+
69
+
70
+ @dataclass
71
+ class Vendor(DataClassDictMixin):
72
+ """Data class for vendor data."""
73
+
74
+ id: int
75
+ name: str
76
+ external_id: str
77
+ registered: datetime
File without changes
@@ -0,0 +1,232 @@
1
+ """Asynchronous Python client for Spoolman."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import socket
7
+ from dataclasses import dataclass
8
+ from importlib import metadata
9
+ from typing import Any, Self, cast
10
+
11
+ from aiohttp import ClientError, ClientSession
12
+ from aiohttp.hdrs import METH_GET
13
+ from yarl import URL
14
+
15
+ from .exceptions import SpoolmanConnectionError, SpoolmanError, SpoolmanResponseError
16
+ from .models import Filament, Info, Spool, Vendor
17
+
18
+ VERSION = metadata.version(__package__)
19
+
20
+
21
+ @dataclass
22
+ class Spoolman:
23
+ """Main class for handling connections with the Spoolman API."""
24
+
25
+ host: str
26
+ port: int = 7912
27
+
28
+ request_timeout: float = 10.0
29
+ session: ClientSession | None = None
30
+
31
+ _close_session: bool = False
32
+
33
+ async def _request(
34
+ self,
35
+ uri: str,
36
+ *,
37
+ method: str = METH_GET,
38
+ params: dict[str, Any] | None = None,
39
+ ) -> Any:
40
+ """Handle a request to the Spoolman API.
41
+
42
+ Args:
43
+ ----
44
+ uri: Request URI, without '/api/', for example, 'status'.
45
+ method: HTTP method to use.
46
+ params: Extra options to improve or limit the response.
47
+
48
+ Returns:
49
+ -------
50
+ A Python dictionary (JSON decoded) with the response from
51
+ the Spoolman API.
52
+
53
+ Raises:
54
+ ------
55
+ SpoolmanConnectionError: If the connection to the API fails.
56
+ SpoolmanError: If the API returns an error.
57
+ SpoolmanResponseError: If the API returns a error.
58
+
59
+ """
60
+ url = URL.build(
61
+ scheme="http",
62
+ host=self.host,
63
+ port=int(self.port),
64
+ path="/api/v1/",
65
+ ).join(URL(uri))
66
+
67
+ headers = {
68
+ "User-Agent": f"PythonSpoolman/{VERSION}",
69
+ "Accept": "application/json",
70
+ }
71
+
72
+ if self.session is None:
73
+ self.session = ClientSession()
74
+ self._close_session = True
75
+
76
+ try:
77
+ async with asyncio.timeout(self.request_timeout):
78
+ response = await self.session.request(
79
+ method,
80
+ url,
81
+ params=params,
82
+ headers=headers,
83
+ )
84
+
85
+ if response.status == 404:
86
+ response_data = await response.json()
87
+ raise SpoolmanResponseError(response_data, response.status)
88
+
89
+ response.raise_for_status()
90
+
91
+ except TimeoutError as exception:
92
+ msg = "Timeout occurred while connecting to the Spoolman API."
93
+ raise SpoolmanConnectionError(msg) from exception
94
+ except (ClientError, socket.gaierror) as exception:
95
+ msg = "Error occurred while connecting to the Spoolman API."
96
+ raise SpoolmanConnectionError(msg) from exception
97
+
98
+ content_type = response.headers.get("content-type", "")
99
+ if "application/json" not in content_type:
100
+ text = await response.text()
101
+ msg = "Unexpected response from the Spoolman API."
102
+ raise SpoolmanError(
103
+ msg,
104
+ {"Content-Type": content_type, "Response": text},
105
+ )
106
+
107
+ return cast(dict[str, Any], await response.json())
108
+
109
+ async def info(self) -> Info:
110
+ """Get information about the Spoolman API.
111
+
112
+ Returns
113
+ -------
114
+ A dictionary with information about the Spoolman API.
115
+
116
+ """
117
+ response = await self._request("info")
118
+ return Info.from_dict(response)
119
+
120
+ async def health(self) -> bool:
121
+ """Check the health of the Spoolman API.
122
+
123
+ Returns
124
+ -------
125
+ True if the API is healthy, False otherwise.
126
+
127
+ """
128
+ response: dict[str, str] = await self._request("health")
129
+ return response["status"] == "healthy"
130
+
131
+ async def get_filaments(self) -> list[Filament]:
132
+ """Get a list of all available filaments.
133
+
134
+ Returns
135
+ -------
136
+ A list with filament data.
137
+
138
+ """
139
+ response = await self._request("filament")
140
+ return [Filament.from_dict(item) for item in response]
141
+
142
+ async def get_filament(self, filament_id: int) -> Filament:
143
+ """Get a specific filament by ID.
144
+
145
+ Args:
146
+ ----
147
+ filament_id: The ID of the filament to retrieve.
148
+
149
+ Returns:
150
+ -------
151
+ A dictionary with the filament data.
152
+
153
+ """
154
+ response = await self._request(f"filament/{filament_id}")
155
+ return Filament.from_dict(response)
156
+
157
+ async def get_spools(self) -> list[Spool]:
158
+ """Get a list of all available spools.
159
+
160
+ Returns
161
+ -------
162
+ A list with spool data.
163
+
164
+ """
165
+ response = await self._request("spool")
166
+ return [Spool.from_dict(item) for item in response]
167
+
168
+ async def get_spool(self, spool_id: int) -> Spool:
169
+ """Get a specific spool by ID.
170
+
171
+ Args:
172
+ ----
173
+ spool_id: The ID of the spool to retrieve.
174
+
175
+ Returns:
176
+ -------
177
+ A dictionary with the spool data.
178
+
179
+ """
180
+ response = await self._request(f"spool/{spool_id}")
181
+ return Spool.from_dict(response)
182
+
183
+ async def get_vendors(self) -> list[Vendor]:
184
+ """Get a list of all available vendors.
185
+
186
+ Returns
187
+ -------
188
+ A list with vendor data.
189
+
190
+ """
191
+ response = await self._request("vendor")
192
+ return [Vendor.from_dict(item) for item in response]
193
+
194
+ async def get_vendor(self, vendor_id: int) -> Vendor:
195
+ """Get a specific vendor by ID.
196
+
197
+ Args:
198
+ ----
199
+ vendor_id: The ID of the vendor to retrieve.
200
+
201
+ Returns:
202
+ -------
203
+ A dictionary with the vendor data.
204
+
205
+ """
206
+ response = await self._request(f"vendor/{vendor_id}")
207
+ return Vendor.from_dict(response)
208
+
209
+ async def close(self) -> None:
210
+ """Close open client session."""
211
+ if self.session and self._close_session:
212
+ await self.session.close()
213
+
214
+ async def __aenter__(self) -> Self:
215
+ """Async enter.
216
+
217
+ Returns
218
+ -------
219
+ The Spoolman object.
220
+
221
+ """
222
+ return self
223
+
224
+ async def __aexit__(self, *_exc_info: object) -> None:
225
+ """Async exit.
226
+
227
+ Args:
228
+ ----
229
+ _exc_info: Exec type.
230
+
231
+ """
232
+ await self.close()