phue2 0.0.1.dev280__tar.gz → 0.0.3__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.
Files changed (40) hide show
  1. phue2-0.0.3/.cursor/rules/docs.mdc +14 -0
  2. phue2-0.0.3/.cursor/rules/python-style.mdc +36 -0
  3. {phue2-0.0.1.dev280 → phue2-0.0.3}/PKG-INFO +1 -1
  4. {phue2-0.0.1.dev280 → phue2-0.0.3}/pyproject.toml +2 -8
  5. {phue2-0.0.1.dev280 → phue2-0.0.3}/src/phue2/__main__.py +11 -1
  6. {phue2-0.0.1.dev280 → phue2-0.0.3}/src/phue2/bridge.py +10 -6
  7. {phue2-0.0.1.dev280 → phue2-0.0.3}/tests/test_bridge.py +27 -0
  8. {phue2-0.0.1.dev280 → phue2-0.0.3}/.github/workflows/lint.yml +0 -0
  9. {phue2-0.0.1.dev280 → phue2-0.0.3}/.github/workflows/publish.yml +0 -0
  10. {phue2-0.0.1.dev280 → phue2-0.0.3}/.github/workflows/test.yml +0 -0
  11. {phue2-0.0.1.dev280 → phue2-0.0.3}/.gitignore +0 -0
  12. {phue2-0.0.1.dev280 → phue2-0.0.3}/.pre-commit-config.yaml +0 -0
  13. {phue2-0.0.1.dev280 → phue2-0.0.3}/LICENSE +0 -0
  14. {phue2-0.0.1.dev280 → phue2-0.0.3}/README.md +0 -0
  15. {phue2-0.0.1.dev280 → phue2-0.0.3}/examples/connect_bridge.py +0 -0
  16. {phue2-0.0.1.dev280 → phue2-0.0.3}/examples/flicker.py +0 -0
  17. {phue2-0.0.1.dev280 → phue2-0.0.3}/examples/hue-rainbow.py +0 -0
  18. {phue2-0.0.1.dev280 → phue2-0.0.3}/examples/random_colors.py +0 -0
  19. {phue2-0.0.1.dev280 → phue2-0.0.3}/examples/repros/smart_home.py +0 -0
  20. {phue2-0.0.1.dev280 → phue2-0.0.3}/examples/rgb_colors.py +0 -0
  21. {phue2-0.0.1.dev280 → phue2-0.0.3}/examples/sine_wave_lights.py +0 -0
  22. {phue2-0.0.1.dev280 → phue2-0.0.3}/examples/tk_gui_complex.py +0 -0
  23. {phue2-0.0.1.dev280 → phue2-0.0.3}/examples/tk_gui_hsb.py +0 -0
  24. {phue2-0.0.1.dev280 → phue2-0.0.3}/examples/tk_gui_simple.py +0 -0
  25. {phue2-0.0.1.dev280 → phue2-0.0.3}/justfile +0 -0
  26. {phue2-0.0.1.dev280 → phue2-0.0.3}/src/phue2/__init__.py +0 -0
  27. {phue2-0.0.1.dev280 → phue2-0.0.3}/src/phue2/_internal/__init__.py +0 -0
  28. {phue2-0.0.1.dev280 → phue2-0.0.3}/src/phue2/_internal/console.py +0 -0
  29. {phue2-0.0.1.dev280 → phue2-0.0.3}/src/phue2/exceptions.py +0 -0
  30. {phue2-0.0.1.dev280 → phue2-0.0.3}/src/phue2/group.py +0 -0
  31. {phue2-0.0.1.dev280 → phue2-0.0.3}/src/phue2/light.py +0 -0
  32. {phue2-0.0.1.dev280 → phue2-0.0.3}/src/phue2/scene.py +0 -0
  33. {phue2-0.0.1.dev280 → phue2-0.0.3}/src/phue2/sensor.py +0 -0
  34. {phue2-0.0.1.dev280 → phue2-0.0.3}/tests/__init__.py +0 -0
  35. {phue2-0.0.1.dev280 → phue2-0.0.3}/tests/samples.py +0 -0
  36. {phue2-0.0.1.dev280 → phue2-0.0.3}/tests/test_basic_import.py +0 -0
  37. {phue2-0.0.1.dev280 → phue2-0.0.3}/tests/test_cli.py +0 -0
  38. {phue2-0.0.1.dev280 → phue2-0.0.3}/tests/test_request.py +0 -0
  39. {phue2-0.0.1.dev280 → phue2-0.0.3}/tests/test_scene.py +0 -0
  40. {phue2-0.0.1.dev280 → phue2-0.0.3}/uv.lock +0 -0
@@ -0,0 +1,14 @@
1
+ ---
2
+ description: style and tone for documentation
3
+ globs: *.mdx
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # tone
8
+ - casual, clear and concise
9
+ - use "you" to refer to the user (e.g. "Foo is great when you want Bar")
10
+
11
+ # content
12
+ - breathable
13
+ - makes good use of admonitions and mintlify's features like <CodeGroup> and <Tip>
14
+ - interspersed with practical and simple examples with output in <Accordian> where apt
@@ -0,0 +1,36 @@
1
+ ---
2
+ description: how to write, test and run python
3
+ globs: *.py
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Python Style
8
+
9
+ ## Design
10
+ - aggressively minimal and elegant
11
+ - prefer functional over OOP
12
+ - keep implementation details "private" (e.g. def _impl)
13
+
14
+ ## Type Hints
15
+ - Marvin supports Python 3.10+
16
+ - Use modern syntax and full type annotations
17
+ - Use | instead of Union
18
+ - Use builtins like list, dict instead of typing.List and typing.Dict
19
+ - use | None instead of Optional
20
+ - Always type optional keyword arguments correctly e.g. def f(x: int | None = None)
21
+
22
+ ## Running Commands
23
+ `uv` gives us superpowers to resolve deps fast and on the fly. no more pip or fussing with venvs
24
+
25
+ ### Install dependencies
26
+ - install project deps: `uv sync`
27
+ - install project deps with an extra: `uv sync --extra foo`
28
+
29
+ ### Running script
30
+ - run script with existing project deps: `uv run some/script.py`
31
+ - run script additional deps on the fly: `uv run --with pandas script.py`
32
+
33
+ ### Testing
34
+ - test all: `uv run pytest`
35
+ - test all with 3 runners: `uv run pytest -n3`
36
+ - test certain folder, only matching cases: `uv run pytest tests/basic -k some_test_fn_subtr`
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: phue2
3
- Version: 0.0.1.dev280
3
+ Version: 0.0.3
4
4
  Summary: A Philips Hue Python library
5
5
  Author: Nathanaël Lécaudé, Nathan Nowack
6
6
  License: MIT
@@ -28,20 +28,14 @@ dev = [
28
28
 
29
29
 
30
30
  [build-system]
31
- requires = ["hatchling", "uv-dynamic-versioning>=0.7.0"]
31
+ requires = ["hatchling", "hatch-vcs"]
32
32
  build-backend = "hatchling.build"
33
33
 
34
34
  [tool.hatch.build.targets.wheel]
35
35
  packages = ["src/phue2"]
36
36
 
37
37
  [tool.hatch.version]
38
- source = "uv-dynamic-versioning"
39
-
40
- [tool.uv-dynamic-versioning]
41
- vcs = "git"
42
- style = "pep440"
43
- bump = true
44
- metadata = false
38
+ source = "vcs"
45
39
 
46
40
 
47
41
  [tool.pytest.ini_options]
@@ -60,6 +60,12 @@ def parse_args(
60
60
  )
61
61
  parser.add_argument("--config-file-path", help="Path to the config file")
62
62
  parser.add_argument("--debug", action="store_true", help="Enable debug logging")
63
+ parser.add_argument(
64
+ "--no-save-config",
65
+ action="store_false",
66
+ dest="save_config",
67
+ help="Do not save connection details to the config file",
68
+ )
63
69
 
64
70
  # Command subparsers
65
71
  subparsers = parser.add_subparsers(dest="command", help="Command to execute")
@@ -161,7 +167,11 @@ def main(argv: list[str] | None = None) -> int:
161
167
  console.info(f"Connecting to bridge at {args.host}...")
162
168
  while True:
163
169
  try:
164
- bridge = Bridge(args.host, config_file_path=args.config_file_path)
170
+ bridge = Bridge(
171
+ args.host,
172
+ config_file_path=args.config_file_path,
173
+ save_config=args.save_config,
174
+ )
165
175
  console.success("Successfully connected to the bridge!")
166
176
  break
167
177
  except PhueRegistrationException:
@@ -46,6 +46,7 @@ class Bridge:
46
46
  username: str | None = None,
47
47
  config_file_path: str | None = None,
48
48
  timeout: int = 10,
49
+ save_config: bool = True,
49
50
  ):
50
51
  """Initialization function.
51
52
 
@@ -54,6 +55,7 @@ class Bridge:
54
55
  username: Optional username for the bridge
55
56
  config_file_path: Optional path to the configuration file
56
57
  timeout: Request timeout in seconds (default: 10)
58
+ save_config: If False, don't save the config file (default: True)
57
59
  """
58
60
  # Determine config file path
59
61
  if config_file_path is not None:
@@ -89,6 +91,7 @@ class Bridge:
89
91
  self.ip = ip
90
92
  self._username = username
91
93
  self.timeout = timeout
94
+ self.save_config = save_config
92
95
  self.lights_by_id: dict[int, Light] = {}
93
96
  self.lights_by_name: dict[str, Light] = {}
94
97
  self.sensors_by_id: dict[int, Sensor] = {}
@@ -233,12 +236,13 @@ class Bridge:
233
236
  for line in response:
234
237
  for key in line:
235
238
  if "success" in key:
236
- with open(self.config_file_path, "w") as f:
237
- logger.info(
238
- "Writing configuration file to " + self.config_file_path
239
- )
240
- f.write(json.dumps({self.ip: line["success"]}))
241
- logger.info("Reconnecting to the bridge")
239
+ if self.save_config:
240
+ with open(self.config_file_path, "w") as f:
241
+ logger.info(
242
+ "Writing configuration file to " + self.config_file_path
243
+ )
244
+ f.write(json.dumps({self.ip: line["success"]}))
245
+ logger.info("Reconnecting to the bridge")
242
246
  self._username = line["success"]["username"]
243
247
  return
244
248
  if "error" in key:
@@ -90,3 +90,30 @@ def test_config_file(tmp_path: Path) -> None:
90
90
  # Test loading from config
91
91
  bridge2 = phue2.Bridge(config_file_path=str(config_file))
92
92
  assert bridge2.username == "testuser"
93
+
94
+
95
+ def test_no_save_config(tmp_path: Path) -> None:
96
+ """Test that the config file is not saved when save_config is False."""
97
+ config_file = tmp_path / ".python_hue"
98
+
99
+ with respx.mock(assert_all_called=True) as mock:
100
+ mock.post("http://192.168.1.100/api", name="create_user").mock(
101
+ return_value=httpx.Response(
102
+ 200, json=[{"success": {"username": "nosavetest"}}]
103
+ )
104
+ )
105
+
106
+ # Create a bridge with save_config=False
107
+ bridge = phue2.Bridge(
108
+ ip="192.168.1.100",
109
+ config_file_path=str(config_file),
110
+ save_config=False,
111
+ )
112
+
113
+ # Verify config file was NOT created and username is set
114
+ assert not config_file.exists()
115
+ assert bridge.username == "nosavetest"
116
+
117
+ # Verify that trying to connect again without IP fails (as config wasn't saved)
118
+ with pytest.raises(phue2.PhueException):
119
+ phue2.Bridge(config_file_path=str(config_file))
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes