Compare commits

..

3 Commits

Author SHA1 Message Date
47917c9c34
Bump version
All checks were successful
build / build (push) Successful in 1m38s
build / build (pull_request) Successful in 1m14s
2024-11-28 21:53:16 +01:00
b85f50ea4c
Fix mypy checks 2024-11-28 21:52:57 +01:00
15d2928771
Convert from poetry to uv 2024-11-28 21:42:45 +01:00
6 changed files with 385 additions and 202 deletions

1
.python-version Normal file
View File

@ -0,0 +1 @@
3.12

View File

@ -1,69 +1,12 @@
{ {
"nodes": { "nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nix-github-actions": {
"inputs": {
"nixpkgs": [
"poetry2nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1703863825,
"narHash": "sha256-rXwqjtwiGKJheXB43ybM8NwWB8rO2dSRrEqes0S7F5Y=",
"owner": "nix-community",
"repo": "nix-github-actions",
"rev": "5163432afc817cf8bd1f031418d1869e4c9d5547",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nix-github-actions",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1724224976, "lastModified": 1732521221,
"narHash": "sha256-Z/ELQhrSd7bMzTO8r7NZgi9g5emh+aRKoCdaAv5fiO0=", "narHash": "sha256-2ThgXBUXAE1oFsVATK1ZX9IjPcS4nKFOAjhPNKuiMn0=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "c374d94f1536013ca8e92341b540eba4c22f9c62", "rev": "4633a7c72337ea8fd23a4f2ba3972865e3ec685d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -73,99 +16,80 @@
"type": "github" "type": "github"
} }
}, },
"poetry2nix": { "pyproject-build-systems": {
"inputs": { "inputs": {
"flake-utils": "flake-utils_2",
"nix-github-actions": "nix-github-actions",
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
], ],
"systems": "systems_3", "pyproject-nix": [
"treefmt-nix": "treefmt-nix" "pyproject-nix"
],
"uv2nix": [
"uv2nix"
]
}, },
"locked": { "locked": {
"lastModified": 1724208502, "lastModified": 1732506638,
"narHash": "sha256-TCRcEPSfgAw/t7kClmlr23s591N06mQCrhzlAO7cyFw=", "narHash": "sha256-aIjGCa8Lvhb8QnbHPOtkZ6yTrb8KURRlYzlo7UaBeac=",
"owner": "nix-community", "owner": "pyproject-nix",
"repo": "poetry2nix", "repo": "build-system-pkgs",
"rev": "884b66152b0c625b8220b570a31dc7acc36749a3", "rev": "70c271e7a64199c71c9dbcbe513c7b2402573789",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "nix-community", "owner": "pyproject-nix",
"repo": "poetry2nix", "repo": "build-system-pkgs",
"type": "github"
}
},
"pyproject-nix": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1732502826,
"narHash": "sha256-tgInDnNOGd5haarL7i94TZ/TqOR1UHvYliw+Db0lk6U=",
"owner": "pyproject-nix",
"repo": "pyproject.nix",
"rev": "fb87b3bad09fbd71b448e2f71f0337087430dbc7",
"type": "github"
},
"original": {
"owner": "pyproject-nix",
"repo": "pyproject.nix",
"type": "github" "type": "github"
} }
}, },
"root": { "root": {
"inputs": { "inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"poetry2nix": "poetry2nix" "pyproject-build-systems": "pyproject-build-systems",
"pyproject-nix": "pyproject-nix",
"uv2nix": "uv2nix"
} }
}, },
"systems": { "uv2nix": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_3": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"id": "systems",
"type": "indirect"
}
},
"treefmt-nix": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"poetry2nix",
"nixpkgs" "nixpkgs"
],
"pyproject-nix": [
"pyproject-nix"
] ]
}, },
"locked": { "locked": {
"lastModified": 1719749022, "lastModified": 1732759365,
"narHash": "sha256-ddPKHcqaKCIFSFc/cvxS14goUhCOAwsM1PbMr0ZtHMg=", "narHash": "sha256-kOOlzfAsFpfiLltRbqFysVhT86erXVe4TZCNIq5zv0o=",
"owner": "numtide", "owner": "pyproject-nix",
"repo": "treefmt-nix", "repo": "uv2nix",
"rev": "8df5ff62195d4e67e2264df0b7f5e8c9995fd0bd", "rev": "f932943b62a0b4fade224f18df13558f8015dd99",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "numtide", "owner": "pyproject-nix",
"repo": "treefmt-nix", "repo": "uv2nix",
"type": "github" "type": "github"
} }
} }

196
flake.nix
View File

@ -1,64 +1,166 @@
{ {
description = "Application packaged using poetry2nix"; description = "Set Philips Hue lights using MQTT";
inputs = { inputs = {
flake-utils.url = "github:numtide/flake-utils";
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
poetry2nix = {
url = "github:nix-community/poetry2nix"; pyproject-nix = {
url = "github:pyproject-nix/pyproject.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
uv2nix = {
url = "github:pyproject-nix/uv2nix";
inputs.pyproject-nix.follows = "pyproject-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
pyproject-build-systems = {
url = "github:pyproject-nix/build-system-pkgs";
inputs.pyproject-nix.follows = "pyproject-nix";
inputs.uv2nix.follows = "uv2nix";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
}; };
outputs = { self, nixpkgs, flake-utils, poetry2nix }: outputs =
{ {
overlays.default = final: prev: { self,
huecli = self.packages.${prev.system}.default; nixpkgs,
uv2nix,
pyproject-nix,
pyproject-build-systems,
...
}:
let
inherit (nixpkgs) lib;
forAllSystems = lib.genAttrs lib.systems.flakeExposed;
workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; };
overlay = workspace.mkPyprojectOverlay {
sourcePreference = "wheel";
}; };
}
// editableOverlay = workspace.mkEditablePyprojectOverlay {
flake-utils.lib.eachDefaultSystem (system: root = "$REPO_ROOT";
let };
# see https://github.com/nix-community/poetry2nix/tree/master#api for more functions and examples.
pkgs = nixpkgs.legacyPackages.${system}; # Python sets grouped per system
inherit (poetry2nix.lib.mkPoetry2Nix { inherit pkgs; }) mkPoetryApplication defaultPoetryOverrides; pythonSets = forAllSystems (
pypkgs-build-requirements = { system:
paho-mqtt = [ "hatch-vcs" ]; let
typer-slim = [ "pdm-backend" ]; pkgs = nixpkgs.legacyPackages.${system};
}; inherit (pkgs) stdenv;
p2n-overrides = defaultPoetryOverrides.extend (final: prev:
builtins.mapAttrs # Base Python package set from pyproject.nix
(package: build-requirements: baseSet = pkgs.callPackage pyproject-nix.build.packages {
(builtins.getAttr package prev).overridePythonAttrs (old: {
buildInputs = (old.buildInputs or [ ]) ++ (builtins.map (pkg: if builtins.isString pkg then builtins.getAttr pkg prev else pkg) build-requirements);
})
)
pypkgs-build-requirements
);
in
{
packages = {
huecli = mkPoetryApplication {
projectDir = ./.;
overrides = p2n-overrides;
python = pkgs.python312; python = pkgs.python312;
nativeBuildInputs = [ pkgs.installShellFiles ]; };
postInstall = ''
installShellCompletion --cmd huecli \ # An overlay of build fixups & test additions
pyprojectOverrides = (
final: prev: {
huecli = prev.huecli.overrideAttrs (old: {
# Add tests to passthru.tests
#
# These attribute are used in Flake checks.
passthru = old.passthru // {
tests = (old.tests or { }) // {
# Run mypy checks
mypy =
let
venv = final.mkVirtualEnv "huecli-typing-env" {
huecli = [ "typing" ];
};
in
stdenv.mkDerivation {
name = "${final.huecli.name}-mypy";
inherit (final.huecli) src;
nativeBuildInputs = [
venv
];
dontConfigure = true;
dontInstall = true;
buildPhase = ''
mypy --version
mkdir $out
mypy --strict huecli --junit-xml $out/junit.xml
'';
};
};
};
});
}
);
in
baseSet.overrideScope (
lib.composeManyExtensions [
pyproject-build-systems.overlays.default
overlay
pyprojectOverrides
]
)
);
in
{
checks = forAllSystems (
system:
let
pythonSet = pythonSets.${system};
in
# Inherit tests from passthru.tests into flake checks
pythonSet.huecli.passthru.tests
);
packages = forAllSystems (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
pythonSet = pythonSets.${system};
in
{
default = (pythonSet.mkVirtualEnv "huecli" workspace.deps.default).overrideAttrs (
_final: prev: {
nativeBuildInputs = prev.nativeBuildInputs ++ [ pkgs.installShellFiles ];
postInstall = ''
installShellCompletion --cmd huecli \
--bash <($out/bin/huecli --show-completion bash) \ --bash <($out/bin/huecli --show-completion bash) \
--zsh <($out/bin/huecli --show-completion zsh) \ --zsh <($out/bin/huecli --show-completion zsh) \
--fish <($out/bin/huecli --show-completion fish) --fish <($out/bin/huecli --show-completion fish)
'';
}
);
}
);
# Use an editable Python set for development.
devShells = forAllSystems (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
editablePythonSet = pythonSets.${system}.overrideScope editableOverlay;
venv = editablePythonSet.mkVirtualEnv "huecli-dev-env" {
huecli = [ "dev" ];
};
in
{
default = pkgs.mkShell {
packages = [
venv
pkgs.uv
];
shellHook = ''
unset PYTHONPATH
export REPO_ROOT=$(git rev-parse --show-toplevel)
export UV_NO_SYNC=1
''; '';
}; };
default = self.packages.${system}.huecli; }
}; );
};
devShells.default = pkgs.mkShell {
inputsFrom = [ self.packages.${system}.huecli ];
packages = [
pkgs.ruff
pkgs.poetry
];
};
});
} }

View File

@ -25,7 +25,7 @@ NAME_TO_ID = {
"office": "0x001788010e371aa4", "office": "0x001788010e371aa4",
"all": "all_lights", "all": "all_lights",
"infuse": "infuse_group", "infuse": "infuse_group",
"living_room": "living_room" "living_room": "living_room",
} }
COLOR_MAP = { COLOR_MAP = {
"red": (0.6942, 0.2963), "red": (0.6942, 0.2963),
@ -50,14 +50,14 @@ class LightID(str, Enum):
livingroom = "living_room" livingroom = "living_room"
def get_mqtt_broker(): def get_mqtt_broker() -> str:
if "HUECLI_BROKER" in os.environ: if "HUECLI_BROKER" in os.environ:
return os.environ["HUECLI_BROKER"] return os.environ["HUECLI_BROKER"]
else: else:
return MQTT_BROKER return MQTT_BROKER
def complete_color(incomplete: str): def complete_color(incomplete: str) -> list[str]:
completion = [] completion = []
for color in COLOR_MAP: for color in COLOR_MAP:
if color.startswith(incomplete): if color.startswith(incomplete):
@ -65,7 +65,7 @@ def complete_color(incomplete: str):
return completion return completion
def complete_id(incomplete: str): def complete_id(incomplete: str) -> list[str]:
completion = [] completion = []
for id in NAME_TO_ID: for id in NAME_TO_ID:
if id.startswith(incomplete): if id.startswith(incomplete):
@ -73,7 +73,7 @@ def complete_id(incomplete: str):
return completion return completion
def complete_state(incomplete: str): def complete_state(incomplete: str) -> list[str]:
states = ["on", "off"] states = ["on", "off"]
completion = [] completion = []
for id in states: for id in states:
@ -82,7 +82,7 @@ def complete_state(incomplete: str):
return completion return completion
def rgb_to_xy(red, green, blue) -> XYColor: def rgb_to_xy(red: float, green: float, blue: float) -> XYColor:
"""conversion of RGB colors to CIE1931 XY colors """conversion of RGB colors to CIE1931 XY colors
Formulas implemented from: https://gist.github.com/popcorn245/30afa0f98eea1c2fd34d Formulas implemented from: https://gist.github.com/popcorn245/30afa0f98eea1c2fd34d
@ -132,7 +132,7 @@ def set_color(
color: Annotated[ color: Annotated[
str, typer.Argument(help="Color to set", autocompletion=complete_color) str, typer.Argument(help="Color to set", autocompletion=complete_color)
], ],
): ) -> None:
""" """
Set the color of ID to COLOR where COLOR is either a known color value, Set the color of ID to COLOR where COLOR is either a known color value,
or a comma separated RGB value, like "0.1,0.2,0.3". or a comma separated RGB value, like "0.1,0.2,0.3".
@ -158,7 +158,7 @@ def set_state(
LightState, LightState,
typer.Argument(help="State of light.", autocompletion=complete_state), typer.Argument(help="State of light.", autocompletion=complete_state),
], ],
): ) -> None:
""" """
Set the state of ID to STATE Set the state of ID to STATE
""" """
@ -175,7 +175,7 @@ def set_brightness(
LightID, typer.Argument(help="ID of light.", autocompletion=complete_id) LightID, typer.Argument(help="ID of light.", autocompletion=complete_id)
], ],
brightness: int, brightness: int,
): ) -> None:
""" """
Set brigthness of ID to BRIGHTNESS Set brigthness of ID to BRIGHTNESS
""" """
@ -186,6 +186,7 @@ def set_brightness(
payload = json.dumps({"brightness": brightness}) payload = json.dumps({"brightness": brightness})
pub.single(topic, payload, hostname=get_mqtt_broker()) pub.single(topic, payload, hostname=get_mqtt_broker())
@app.command() @app.command()
@app.command("get", hidden=True) @app.command("get", hidden=True)
def get_state( def get_state(
@ -193,9 +194,10 @@ def get_state(
LightID, typer.Argument(help="ID of light.", autocompletion=complete_id) LightID, typer.Argument(help="ID of light.", autocompletion=complete_id)
], ],
as_json: Annotated[ as_json: Annotated[
bool, typer.Option("--json", help="Print state as json."), bool,
] = False typer.Option("--json", help="Print state as json."),
): ] = False,
) -> None:
""" """
Get the state of ID Get the state of ID
""" """
@ -204,15 +206,16 @@ def get_state(
resp_topic = f"zigbee2mqtt/{str_id}" resp_topic = f"zigbee2mqtt/{str_id}"
payload = json.dumps({"state": ""}) payload = json.dumps({"state": ""})
pub.single(topic, payload, hostname=get_mqtt_broker()) pub.single(topic, payload, hostname=get_mqtt_broker())
resp = sub.simple(resp_topic, hostname=get_mqtt_broker()) resp = sub.simple(resp_topic, hostname=get_mqtt_broker()) # type: ignore[no-untyped-call]
data = json.loads(resp.payload.decode("utf-8")) data = json.loads(resp.payload.decode("utf-8"))
if as_json: if as_json:
print(json.dumps(data)) print(json.dumps(data))
else: else:
print(f"{data['state']}") print(f"{data['state']}")
@app.command() @app.command()
def version(): def version() -> None:
""" """
Print huecli version Print huecli version
""" """
@ -244,7 +247,7 @@ def _parse_rgb_color(r: float, g: float, b: float) -> XYColor:
raise ValueError("RGB values must be between 0 and 255 or 0.0 and 1.0") raise ValueError("RGB values must be between 0 and 255 or 0.0 and 1.0")
def main(): def main() -> None:
app() app()

View File

@ -1,19 +1,33 @@
[tool.poetry] [project]
name = "huecli" name = "huecli"
version = "0.1.6" version = "0.1.7"
description = "Set Philips Hue lights using MQTT" description = "Set Philips Hue lights using MQTT"
authors = ["Torjus Håkestad <torjus@uio.no>"] authors = [
license = "MIT" { name = "Torjus Håkestad", email = "torjus@usit.uio.no" },
]
readme = "README.md" readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"paho-mqtt>=2.1.0",
"typer-slim>=0.13.1",
]
[tool.poetry.dependencies] [project.scripts]
python = ">=3.11"
paho-mqtt = ">=2.1.0"
typer-slim = ">=0.12.3"
[tool.poetry.scripts]
huecli = "huecli.__main__:main" huecli = "huecli.__main__:main"
[build-system] [tool.uv]
requires = ["poetry-core"] package = true
build-backend = "poetry.core.masonry.api"
[dependency-groups]
dev = [
{include-group = "linting"},
{include-group = "typing"},
]
typing = [
"mypy>=1.13.0",
]
linting = [
"ruff>=0.8.0",
]

139
uv.lock Normal file
View File

@ -0,0 +1,139 @@
version = 1
requires-python = ">=3.12"
[[package]]
name = "click"
version = "8.1.7"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "platform_system == 'Windows'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 },
]
[[package]]
name = "colorama"
version = "0.4.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
]
[[package]]
name = "huecli"
version = "0.1.6"
source = { editable = "." }
dependencies = [
{ name = "paho-mqtt" },
{ name = "typer-slim" },
]
[package.dev-dependencies]
linting = [
{ name = "ruff" },
]
typing = [
{ name = "mypy" },
]
[package.metadata]
requires-dist = [
{ name = "paho-mqtt", specifier = ">=2.1.0" },
{ name = "typer-slim", specifier = ">=0.13.1" },
]
[package.metadata.requires-dev]
dev = []
linting = [{ name = "ruff", specifier = ">=0.8.0" }]
typing = [{ name = "mypy", specifier = ">=1.13.0" }]
[[package]]
name = "mypy"
version = "1.13.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mypy-extensions" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e8/21/7e9e523537991d145ab8a0a2fd98548d67646dc2aaaf6091c31ad883e7c1/mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e", size = 3152532 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fb/31/c526a7bd2e5c710ae47717c7a5f53f616db6d9097caf48ad650581e81748/mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5", size = 11077900 },
{ url = "https://files.pythonhosted.org/packages/83/67/b7419c6b503679d10bd26fc67529bc6a1f7a5f220bbb9f292dc10d33352f/mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e", size = 10074818 },
{ url = "https://files.pythonhosted.org/packages/ba/07/37d67048786ae84e6612575e173d713c9a05d0ae495dde1e68d972207d98/mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2", size = 12589275 },
{ url = "https://files.pythonhosted.org/packages/1f/17/b1018c6bb3e9f1ce3956722b3bf91bff86c1cefccca71cec05eae49d6d41/mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0", size = 13037783 },
{ url = "https://files.pythonhosted.org/packages/cb/32/cd540755579e54a88099aee0287086d996f5a24281a673f78a0e14dba150/mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2", size = 9726197 },
{ url = "https://files.pythonhosted.org/packages/11/bb/ab4cfdc562cad80418f077d8be9b4491ee4fb257440da951b85cbb0a639e/mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7", size = 11069721 },
{ url = "https://files.pythonhosted.org/packages/59/3b/a393b1607cb749ea2c621def5ba8c58308ff05e30d9dbdc7c15028bca111/mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62", size = 10063996 },
{ url = "https://files.pythonhosted.org/packages/d1/1f/6b76be289a5a521bb1caedc1f08e76ff17ab59061007f201a8a18cc514d1/mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8", size = 12584043 },
{ url = "https://files.pythonhosted.org/packages/a6/83/5a85c9a5976c6f96e3a5a7591aa28b4a6ca3a07e9e5ba0cec090c8b596d6/mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7", size = 13036996 },
{ url = "https://files.pythonhosted.org/packages/b4/59/c39a6f752f1f893fccbcf1bdd2aca67c79c842402b5283563d006a67cf76/mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc", size = 9737709 },
{ url = "https://files.pythonhosted.org/packages/3b/86/72ce7f57431d87a7ff17d442f521146a6585019eb8f4f31b7c02801f78ad/mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a", size = 2647043 },
]
[[package]]
name = "mypy-extensions"
version = "1.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 },
]
[[package]]
name = "paho-mqtt"
version = "2.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/39/15/0a6214e76d4d32e7f663b109cf71fb22561c2be0f701d67f93950cd40542/paho_mqtt-2.1.0.tar.gz", hash = "sha256:12d6e7511d4137555a3f6ea167ae846af2c7357b10bc6fa4f7c3968fc1723834", size = 148848 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c4/cb/00451c3cf31790287768bb12c6bec834f5d292eaf3022afc88e14b8afc94/paho_mqtt-2.1.0-py3-none-any.whl", hash = "sha256:6db9ba9b34ed5bc6b6e3812718c7e06e2fd7444540df2455d2c51bd58808feee", size = 67219 },
]
[[package]]
name = "ruff"
version = "0.8.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b2/d6/a2373f3ba7180ddb44420d2a9d1f1510e1a4d162b3d27282bedcb09c8da9/ruff-0.8.0.tar.gz", hash = "sha256:a7ccfe6331bf8c8dad715753e157457faf7351c2b69f62f32c165c2dbcbacd44", size = 3276537 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ec/77/e889ee3ce7fd8baa3ed1b77a03b9fb8ec1be68be1418261522fd6a5405e0/ruff-0.8.0-py3-none-linux_armv6l.whl", hash = "sha256:fcb1bf2cc6706adae9d79c8d86478677e3bbd4ced796ccad106fd4776d395fea", size = 10518283 },
{ url = "https://files.pythonhosted.org/packages/da/c8/0a47de01edf19fb22f5f9b7964f46a68d0bdff20144d134556ffd1ba9154/ruff-0.8.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:295bb4c02d58ff2ef4378a1870c20af30723013f441c9d1637a008baaf928c8b", size = 10317691 },
{ url = "https://files.pythonhosted.org/packages/41/17/9885e4a0eeae07abd2a4ebabc3246f556719f24efa477ba2739146c4635a/ruff-0.8.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7b1f1c76b47c18fa92ee78b60d2d20d7e866c55ee603e7d19c1e991fad933a9a", size = 9940999 },
{ url = "https://files.pythonhosted.org/packages/3e/cd/46b6f7043597eb318b5f5482c8ae8f5491cccce771e85f59d23106f2d179/ruff-0.8.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb0d4f250a7711b67ad513fde67e8870109e5ce590a801c3722580fe98c33a99", size = 10772437 },
{ url = "https://files.pythonhosted.org/packages/5d/87/afc95aeb8bc78b1d8a3461717a4419c05aa8aa943d4c9cbd441630f85584/ruff-0.8.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e55cce9aa93c5d0d4e3937e47b169035c7e91c8655b0974e61bb79cf398d49c", size = 10299156 },
{ url = "https://files.pythonhosted.org/packages/65/fa/04c647bb809c4d65e8eae1ed1c654d9481b21dd942e743cd33511687b9f9/ruff-0.8.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f4cd64916d8e732ce6b87f3f5296a8942d285bbbc161acee7fe561134af64f9", size = 11325819 },
{ url = "https://files.pythonhosted.org/packages/90/26/7dad6e7d833d391a8a1afe4ee70ca6f36c4a297d3cca83ef10e83e9aacf3/ruff-0.8.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c5c1466be2a2ebdf7c5450dd5d980cc87c8ba6976fb82582fea18823da6fa362", size = 12023927 },
{ url = "https://files.pythonhosted.org/packages/24/a0/be5296dda6428ba8a13bda8d09fbc0e14c810b485478733886e61597ae2b/ruff-0.8.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2dabfd05b96b7b8f2da00d53c514eea842bff83e41e1cceb08ae1966254a51df", size = 11589702 },
{ url = "https://files.pythonhosted.org/packages/26/3f/7602eb11d2886db545834182a9dbe500b8211fcbc9b4064bf9d358bbbbb4/ruff-0.8.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:facebdfe5a5af6b1588a1d26d170635ead6892d0e314477e80256ef4a8470cf3", size = 12782936 },
{ url = "https://files.pythonhosted.org/packages/4c/5d/083181bdec4ec92a431c1291d3fff65eef3ded630a4b55eb735000ef5f3b/ruff-0.8.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87a8e86bae0dbd749c815211ca11e3a7bd559b9710746c559ed63106d382bd9c", size = 11138488 },
{ url = "https://files.pythonhosted.org/packages/b7/23/c12cdef58413cee2436d6a177aa06f7a366ebbca916cf10820706f632459/ruff-0.8.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:85e654f0ded7befe2d61eeaf3d3b1e4ef3894469cd664ffa85006c7720f1e4a2", size = 10744474 },
{ url = "https://files.pythonhosted.org/packages/29/61/a12f3b81520083cd7c5caa24ba61bb99fd1060256482eff0ef04cc5ccd1b/ruff-0.8.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:83a55679c4cb449fa527b8497cadf54f076603cc36779b2170b24f704171ce70", size = 10369029 },
{ url = "https://files.pythonhosted.org/packages/08/2a/c013f4f3e4a54596c369cee74c24870ed1d534f31a35504908b1fc97017a/ruff-0.8.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:812e2052121634cf13cd6fddf0c1871d0ead1aad40a1a258753c04c18bb71bbd", size = 10867481 },
{ url = "https://files.pythonhosted.org/packages/d5/f7/685b1e1d42a3e94ceb25eab23c70bdd8c0ab66a43121ef83fe6db5a58756/ruff-0.8.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:780d5d8523c04202184405e60c98d7595bdb498c3c6abba3b6d4cdf2ca2af426", size = 11237117 },
{ url = "https://files.pythonhosted.org/packages/03/20/401132c0908e8837625e3b7e32df9962e7cd681a4df1e16a10e2a5b4ecda/ruff-0.8.0-py3-none-win32.whl", hash = "sha256:5fdb6efecc3eb60bba5819679466471fd7d13c53487df7248d6e27146e985468", size = 8783511 },
{ url = "https://files.pythonhosted.org/packages/1d/5c/4d800fca7854f62ad77f2c0d99b4b585f03e2d87a6ec1ecea85543a14a3c/ruff-0.8.0-py3-none-win_amd64.whl", hash = "sha256:582891c57b96228d146725975fbb942e1f30a0c4ba19722e692ca3eb25cc9b4f", size = 9559876 },
{ url = "https://files.pythonhosted.org/packages/5b/bc/cc8a6a5ca4960b226dc15dd8fb511dd11f2014ff89d325c0b9b9faa9871f/ruff-0.8.0-py3-none-win_arm64.whl", hash = "sha256:ba93e6294e9a737cd726b74b09a6972e36bb511f9a102f1d9a7e1ce94dd206a6", size = 8939733 },
]
[[package]]
name = "typer-slim"
version = "0.13.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/25/71/bde59468013cf8c87034e6c7cadb97b0478f7e193ff018b5798fd7a9b1c5/typer_slim-0.13.1.tar.gz", hash = "sha256:cc880af8c1d4fafff9dbbbae0b37348372f8633bb0e7d1baa46074c4fcdde810", size = 98740 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b6/f8/d44ccac8b4c09185f0c153d6fd31f02cd1d9a51cfeffde8384913de71e94/typer_slim-0.13.1-py3-none-any.whl", hash = "sha256:13f23cf414fb3de3d9163c4beebe0c6569eabcb85b71c89ffe42887a5332eb3b", size = 44785 },
]
[[package]]
name = "typing-extensions"
version = "4.12.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 },
]