python-omnilogic-local 0.14.4__py3-none-any.whl → 0.15.1__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.
pyomnilogic_local/api.py CHANGED
@@ -1,22 +1,23 @@
1
+ # pylint: disable=too-many-positional-arguments
1
2
  from __future__ import annotations
2
3
 
3
4
  import asyncio
4
5
  import logging
5
- from typing import Literal, overload
6
6
  import xml.etree.ElementTree as ET
7
+ from typing import Literal, overload
7
8
 
8
9
  from .models.filter_diagnostics import FilterDiagnostics
9
10
  from .models.mspconfig import MSPConfig
10
11
  from .models.telemetry import Telemetry
11
12
  from .models.util import to_pydantic
12
- from .protocol import OmniLogicProtocol
13
- from .types import (
13
+ from .omnitypes import (
14
14
  ColorLogicBrightness,
15
15
  ColorLogicShow,
16
16
  ColorLogicSpeed,
17
17
  HeaterMode,
18
18
  MessageType,
19
19
  )
20
+ from .protocol import OmniLogicProtocol
20
21
 
21
22
  _LOGGER = logging.getLogger(__name__)
22
23
 
@@ -30,12 +31,10 @@ class OmniLogicAPI:
30
31
  self._protocol_factory = OmniLogicProtocol
31
32
 
32
33
  @overload
33
- async def async_send_message(self, message_type: MessageType, message: str | None, need_response: Literal[True]) -> str:
34
- ...
34
+ async def async_send_message(self, message_type: MessageType, message: str | None, need_response: Literal[True]) -> str: ...
35
35
 
36
36
  @overload
37
- async def async_send_message(self, message_type: MessageType, message: str | None, need_response: Literal[False]) -> None:
38
- ...
37
+ async def async_send_message(self, message_type: MessageType, message: str | None, need_response: Literal[False]) -> None: ...
39
38
 
40
39
  async def async_send_message(self, message_type: MessageType, message: str | None, need_response: bool = False) -> str | None:
41
40
  """Send a message via the Hayward Omni UDP protocol along with properly handling timeouts and responses.
@@ -97,7 +96,11 @@ class OmniLogicAPI:
97
96
  return await self.async_send_message(MessageType.REQUEST_CONFIGURATION, req_body, True)
98
97
 
99
98
  @to_pydantic(pydantic_type=FilterDiagnostics)
100
- async def async_get_filter_diagnostics(self, pool_id: int, equipment_id: int) -> str:
99
+ async def async_get_filter_diagnostics(
100
+ self,
101
+ pool_id: int,
102
+ equipment_id: int,
103
+ ) -> str:
101
104
  """Retrieve filter diagnostics from the Omni, optionally parse it into a pydantic model.
102
105
 
103
106
  Args:
@@ -146,7 +149,13 @@ class OmniLogicAPI:
146
149
 
147
150
  return await self.async_send_message(MessageType.GET_TELEMETRY, req_body, True)
148
151
 
149
- async def async_set_heater(self, pool_id: int, equipment_id: int, temperature: int, unit: str) -> None:
152
+ async def async_set_heater(
153
+ self,
154
+ pool_id: int,
155
+ equipment_id: int,
156
+ temperature: int,
157
+ unit: str,
158
+ ) -> None:
150
159
  """Set the temperature for a heater on the Omni
151
160
 
152
161
  Args:
@@ -175,7 +184,13 @@ class OmniLogicAPI:
175
184
 
176
185
  return await self.async_send_message(MessageType.SET_HEATER_COMMAND, req_body, False)
177
186
 
178
- async def async_set_solar_heater(self, pool_id: int, equipment_id: int, temperature: int, unit: str) -> None:
187
+ async def async_set_solar_heater(
188
+ self,
189
+ pool_id: int,
190
+ equipment_id: int,
191
+ temperature: int,
192
+ unit: str,
193
+ ) -> None:
179
194
  """Set the solar set point for a heater on the Omni.
180
195
 
181
196
  Args:
@@ -204,7 +219,12 @@ class OmniLogicAPI:
204
219
 
205
220
  return await self.async_send_message(MessageType.SET_SOLAR_SET_POINT_COMMAND, req_body, False)
206
221
 
207
- async def async_set_heater_mode(self, pool_id: int, equipment_id: int, mode: HeaterMode) -> None:
222
+ async def async_set_heater_mode(
223
+ self,
224
+ pool_id: int,
225
+ equipment_id: int,
226
+ mode: HeaterMode,
227
+ ) -> None:
208
228
  """Set what mode (Heat/Cool/Auto) the heater should use.
209
229
 
210
230
  Args:
@@ -232,7 +252,12 @@ class OmniLogicAPI:
232
252
 
233
253
  return await self.async_send_message(MessageType.SET_HEATER_MODE_COMMAND, req_body, False)
234
254
 
235
- async def async_set_heater_enable(self, pool_id: int, equipment_id: int, enabled: int | bool) -> None:
255
+ async def async_set_heater_enable(
256
+ self,
257
+ pool_id: int,
258
+ equipment_id: int,
259
+ enabled: int | bool,
260
+ ) -> None:
236
261
  """async_set_heater_enable handles sending a SetHeaterEnable XML API call to the Hayward Omni pool controller
237
262
 
238
263
  Args:
@@ -436,12 +461,12 @@ class OmniLogicAPI:
436
461
  pool_id: int,
437
462
  equipment_id: int,
438
463
  timed_percent: int,
464
+ cell_type: int,
465
+ op_mode: int,
466
+ sc_timeout: int,
467
+ bow_type: int,
468
+ orp_timeout: int,
439
469
  cfg_state: int = 3,
440
- op_mode: int = 1,
441
- bow_type: int = 0,
442
- cell_type: int = 4,
443
- sc_timeout: int = 24,
444
- orp_timeout: int = 24,
445
470
  ) -> None:
446
471
  body_element = ET.Element("Request", {"xmlns": "http://nextgen.hayward.com/api"})
447
472
 
@@ -472,7 +497,12 @@ class OmniLogicAPI:
472
497
 
473
498
  return await self.async_send_message(MessageType.SET_CHLOR_PARAMS, req_body, False)
474
499
 
475
- async def async_set_chlorinator_superchlorinate(self, pool_id: int, equipment_id: int, enabled: int | bool) -> None:
500
+ async def async_set_chlorinator_superchlorinate(
501
+ self,
502
+ pool_id: int,
503
+ equipment_id: int,
504
+ enabled: int | bool,
505
+ ) -> None:
476
506
  body_element = ET.Element("Request", {"xmlns": "http://nextgen.hayward.com/api"})
477
507
 
478
508
  name_element = ET.SubElement(body_element, "Name")
pyomnilogic_local/cli.py CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env python3
2
-
3
2
  import asyncio
4
3
  import logging
5
4
  import os
@@ -23,6 +23,7 @@ class FilterDiagnostics(BaseModel):
23
23
  orm_mode = True
24
24
 
25
25
  def get_param_by_name(self, name: str) -> int:
26
+ # pylint: disable=not-an-iterable
26
27
  return [param.value for param in self.parameters if param.name == name][0]
27
28
 
28
29
  @staticmethod
@@ -13,8 +13,9 @@ from pydantic.v1 import BaseModel, Field, ValidationError
13
13
  from xmltodict import parse as xml_parse
14
14
 
15
15
  from ..exceptions import OmniParsingException
16
- from ..types import (
16
+ from ..omnitypes import (
17
17
  BodyOfWaterType,
18
+ ChlorinatorCellType,
18
19
  ChlorinatorDispenserType,
19
20
  ColorLogicLightType,
20
21
  ColorLogicShow,
@@ -151,7 +152,9 @@ class MSPChlorinator(OmniBase):
151
152
  enabled: Literal["yes", "no"] = Field(alias="Enabled")
152
153
  timed_percent: int = Field(alias="Timed-Percent")
153
154
  superchlor_timeout: int = Field(alias="SuperChlor-Timeout")
155
+ orp_timeout: int = Field(alias="ORP-Timeout")
154
156
  dispenser_type: ChlorinatorDispenserType | str = Field(alias="Dispenser-Type")
157
+ cell_type: ChlorinatorCellType = Field(alias="Cell-Type")
155
158
  chlorinator_equipment: list[MSPChlorinatorEquip] | None
156
159
 
157
160
  def __init__(self, **data: Any) -> None:
@@ -216,7 +219,7 @@ class MSPBackyard(OmniBase):
216
219
  colorlogic_light: list[MSPColorLogicLight] | None = Field(alias="ColorLogic-Light")
217
220
 
218
221
 
219
- class MSPSchedule(OmniBase):
222
+ class MSPSchedule(OmniBase): # type: ignore[override]
220
223
  omni_type: OmniType = OmniType.SCHEDULE
221
224
  system_id: int = Field(alias="schedule-system-id")
222
225
  bow_id: int = Field(alias="bow-system-id")
@@ -6,7 +6,7 @@ from pydantic.v1 import BaseModel, Field, ValidationError
6
6
  from xmltodict import parse as xml_parse
7
7
 
8
8
  from ..exceptions import OmniParsingException
9
- from ..types import (
9
+ from ..omnitypes import (
10
10
  BackyardState,
11
11
  ChlorinatorOperatingMode,
12
12
  ColorLogicBrightness,
@@ -200,12 +200,10 @@ class Telemetry(BaseModel):
200
200
  TypeVar("VT", SupportsInt, Any)
201
201
 
202
202
  @overload
203
- def xml_postprocessor(path: Any, key: Any, value: SupportsInt) -> tuple[Any, SupportsInt]:
204
- ...
203
+ def xml_postprocessor(path: Any, key: Any, value: SupportsInt) -> tuple[Any, SupportsInt]: ...
205
204
 
206
205
  @overload
207
- def xml_postprocessor(path: Any, key: Any, value: Any) -> tuple[Any, Any]:
208
- ...
206
+ def xml_postprocessor(path: Any, key: Any, value: Any) -> tuple[Any, Any]: ...
209
207
 
210
208
  def xml_postprocessor(path: Any, key: Any, value: SupportsInt | Any) -> tuple[Any, SupportsInt | Any]:
211
209
  """Post process XML to attempt to convert values to int.
@@ -1,5 +1,5 @@
1
- from collections.abc import Awaitable, Callable
2
1
  import logging
2
+ from collections.abc import Awaitable, Callable
3
3
  from typing import Any, Literal, TypeVar, cast, overload
4
4
 
5
5
  from pydantic.v1.utils import GetterDict
@@ -24,17 +24,17 @@ F = TypeVar("F", bound=Callable[..., Awaitable[str]])
24
24
  TPydanticTypes = Telemetry | MSPConfig | FilterDiagnostics
25
25
 
26
26
 
27
- def to_pydantic(pydantic_type: type[TPydanticTypes]) -> Callable[..., Any]:
27
+ def to_pydantic(
28
+ pydantic_type: type[TPydanticTypes],
29
+ ) -> Callable[..., Any]:
28
30
  def inner(func: F, *args: Any, **kwargs: Any) -> F:
29
31
  """Wrap an API function that returns XML and parse it into a Pydantic model"""
30
32
 
31
33
  @overload
32
- async def wrapper(*args: Any, raw: Literal[True], **kwargs: Any) -> str:
33
- ...
34
+ async def wrapper(*args: Any, raw: Literal[True], **kwargs: Any) -> str: ...
34
35
 
35
36
  @overload
36
- async def wrapper(*args: Any, raw: Literal[False], **kwargs: Any) -> TPydanticTypes:
37
- ...
37
+ async def wrapper(*args: Any, raw: Literal[False], **kwargs: Any) -> TPydanticTypes: ...
38
38
 
39
39
  async def wrapper(*args: Any, raw: bool = False, **kwargs: Any) -> TPydanticTypes | str:
40
40
  resp_body = await func(*args, **kwargs)
@@ -1,4 +1,4 @@
1
- from enum import Enum
1
+ from enum import Enum, IntEnum
2
2
 
3
3
  from .util import PrettyEnum
4
4
 
@@ -87,13 +87,38 @@ class BodyOfWaterType(str, PrettyEnum):
87
87
  # Chlorinator status is a bitmask that we still need to figure out
88
88
  # class ChlorinatorStatus(str,Enum):
89
89
  # pass
90
- class ChlorinatorOperatingMode(PrettyEnum):
90
+
91
+
92
+ # I have seen one pool that had an operatingMode of 3, I am not sure what that means, perhaps that is an OFF mode
93
+ class ChlorinatorOperatingMode(IntEnum):
94
+ DISABLED = 0
91
95
  TIMED = 1
92
96
  ORP = 2
97
+ OFF = 3
93
98
 
94
99
 
95
100
  class ChlorinatorDispenserType(str, PrettyEnum):
96
101
  SALT = "SALT_DISPENSING"
102
+ LIQUID = "LIQUID_DISPENSING"
103
+
104
+
105
+ class ChlorinatorCellType(PrettyEnum):
106
+ T3 = "CELL_TYPE_T3"
107
+ T5 = "CELL_TYPE_T5"
108
+ T9 = "CELL_TYPE_T9"
109
+ T15 = "CELL_TYPE_T15"
110
+ LIQUID = "CELL_TYPE_LIQUID"
111
+
112
+ # There is probably an easier way to do this
113
+ def __int__(self) -> int:
114
+ return ChlorinatorCellInt[self.name].value
115
+
116
+
117
+ class ChlorinatorCellInt(IntEnum):
118
+ T3 = 1
119
+ T5 = 2
120
+ T9 = 3
121
+ T15 = 4
97
122
 
98
123
 
99
124
  # Lights
@@ -3,15 +3,15 @@ import logging
3
3
  import random
4
4
  import struct
5
5
  import time
6
- from typing import Any, cast
7
6
  import xml.etree.ElementTree as ET
8
7
  import zlib
8
+ from typing import Any, cast
9
9
 
10
10
  from typing_extensions import Self
11
11
 
12
12
  from .exceptions import OmniTimeoutException
13
13
  from .models.leadmessage import LeadMessage
14
- from .types import ClientType, MessageType
14
+ from .omnitypes import ClientType, MessageType
15
15
 
16
16
  _LOGGER = logging.getLogger(__name__)
17
17
 
@@ -28,7 +28,13 @@ class OmniLogicMessage:
28
28
  compressed: bool = False
29
29
  reserved_2: int = 0
30
30
 
31
- def __init__(self, msg_id: int, msg_type: MessageType, payload: str | None = None, version: str = "1.19") -> None:
31
+ def __init__(
32
+ self,
33
+ msg_id: int,
34
+ msg_type: MessageType,
35
+ payload: str | None = None,
36
+ version: str = "1.19",
37
+ ) -> None:
32
38
  self.id = msg_id
33
39
  self.type = msg_type
34
40
  # If we are speaking the XML API, it seems like we need client_type 0, otherwise we need client_type 1
@@ -67,7 +73,7 @@ class OmniLogicMessage:
67
73
  header = data[:24]
68
74
  rdata: bytes = data[24:]
69
75
 
70
- msg_id, tstamp, vers, msg_type, client_type, res1, compressed, res2 = struct.unpack(cls.header_format, header)
76
+ (msg_id, tstamp, vers, msg_type, client_type, res1, compressed, res2) = struct.unpack(cls.header_format, header)
71
77
  message = cls(msg_id=msg_id, msg_type=MessageType(msg_type), version=vers.decode("utf-8"))
72
78
  message.timestamp = tstamp
73
79
  message.client_type = ClientType(int(client_type))
@@ -125,7 +131,11 @@ class OmniLogicProtocol(asyncio.DatagramProtocol):
125
131
  # eventually time out waiting for it, that way we can deal with the dropped packets
126
132
  message = await self.data_queue.get()
127
133
 
128
- async def _ensure_sent(self, message: OmniLogicMessage, max_attempts: int = 5) -> None:
134
+ async def _ensure_sent(
135
+ self,
136
+ message: OmniLogicMessage,
137
+ max_attempts: int = 5,
138
+ ) -> None:
129
139
  for attempt in range(0, max_attempts):
130
140
  self.transport.sendto(bytes(message))
131
141
 
@@ -143,12 +153,22 @@ class OmniLogicProtocol(asyncio.DatagramProtocol):
143
153
  else:
144
154
  raise OmniTimeoutException("Failed to receive acknowledgement of command, max retries exceeded") from exc
145
155
 
146
- async def send_and_receive(self, msg_type: MessageType, payload: str | None, msg_id: int | None = None) -> str:
156
+ async def send_and_receive(
157
+ self,
158
+ msg_type: MessageType,
159
+ payload: str | None,
160
+ msg_id: int | None = None,
161
+ ) -> str:
147
162
  await self.send_message(msg_type, payload, msg_id)
148
163
  return await self._receive_file()
149
164
 
150
165
  # Send a message that you do NOT need a response to
151
- async def send_message(self, msg_type: MessageType, payload: str | None, msg_id: int | None = None) -> None:
166
+ async def send_message(
167
+ self,
168
+ msg_type: MessageType,
169
+ payload: str | None,
170
+ msg_id: int | None = None,
171
+ ) -> None:
152
172
  # If we aren't sending a specific msg_id, lets randomize it
153
173
  if not msg_id:
154
174
  msg_id = random.randrange(2**32)
pyomnilogic_local/util.py CHANGED
@@ -1,5 +1,5 @@
1
- from enum import Enum
2
1
  import sys
2
+ from enum import Enum
3
3
 
4
4
  if sys.version_info >= (3, 11):
5
5
  from typing import Self
@@ -1,26 +1,19 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: python-omnilogic-local
3
- Version: 0.14.4
3
+ Version: 0.15.1
4
4
  Summary: A library for local control of Hayward OmniHub/OmniLogic pool controllers using their local API
5
- Home-page: https://github.com/cryptk/python-omnilogic-local
6
5
  License: Apache-2.0
7
- Author: cryptk
8
- Author-email: cryptk@users.noreply.github.com
9
- Requires-Python: >=3.10,<4.0
10
- Classifier: Development Status :: 3 - Alpha
11
- Classifier: Intended Audience :: Developers
6
+ Author: Chris Jowett
7
+ Author-email: 421501+cryptk@users.noreply.github.com
8
+ Requires-Python: >=3.10,<3.14
12
9
  Classifier: License :: OSI Approved :: Apache Software License
13
- Classifier: Natural Language :: English
14
- Classifier: Operating System :: OS Independent
15
10
  Classifier: Programming Language :: Python :: 3
16
11
  Classifier: Programming Language :: Python :: 3.10
17
12
  Classifier: Programming Language :: Python :: 3.11
18
13
  Classifier: Programming Language :: Python :: 3.12
19
14
  Classifier: Programming Language :: Python :: 3.13
20
- Classifier: Topic :: Software Development :: Libraries
21
15
  Requires-Dist: pydantic (>=1.10.17)
22
16
  Requires-Dist: xmltodict (>=0.13.0,<0.14.0)
23
- Project-URL: Repository, https://github.com/cryptk/python-omnilogic-local
24
17
  Description-Content-Type: text/markdown
25
18
 
26
19
  # Pyomnilogic Local
@@ -0,0 +1,18 @@
1
+ pyomnilogic_local/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ pyomnilogic_local/api.py,sha256=G991ro3UM-ksVg9gGjTArOvZe41MWsSopbcyqPwwdsU,28390
3
+ pyomnilogic_local/cli.py,sha256=YsLPDuBUM9hDmSiYVfz0H346OtPUgRwiLHfKWUKbD7Q,3930
4
+ pyomnilogic_local/exceptions.py,sha256=7-EYTP-_VgGrA8WWGwQPUE1NGjJEDWB-ovyvSM2iaNY,164
5
+ pyomnilogic_local/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ pyomnilogic_local/models/const.py,sha256=j4HSiPJW5If296yJ-AiIsBI9EdlckF4QkVFIpTLb5C4,51
7
+ pyomnilogic_local/models/filter_diagnostics.py,sha256=74-VjHB-Rf6imeJTYawybA40_m_wb1Dww-Eu4ucGBdo,1577
8
+ pyomnilogic_local/models/leadmessage.py,sha256=XnzXTpLLQzhLQR1OgfAjKmW5N8BBgM7OrntUi1I2VRY,410
9
+ pyomnilogic_local/models/mspconfig.py,sha256=6YUz5e1V25KX0VynT6iwyZyzi8cPUvZwwLSY0M2bTV0,10594
10
+ pyomnilogic_local/models/telemetry.py,sha256=8ncC-10SRQneFmrH-LrnlVTS3Q-oqeXS_EtYKiIfDks,10612
11
+ pyomnilogic_local/models/util.py,sha256=X9jCiU3hFbI0Nc6NSCnvwyVK9XyA3BsiA9W7JYCJmKs,1462
12
+ pyomnilogic_local/omnitypes.py,sha256=rmmBo1xKgsHsX9bjbBh-0YPv4lID1jGrNNU1W1m6zBo,7832
13
+ pyomnilogic_local/protocol.py,sha256=M2vyj8o_PCKyLEswb6JGpUIdyj_swEJC18KrqcQV4kI,10356
14
+ pyomnilogic_local/util.py,sha256=sLkCn2eWbwP4FRiEgYlfmNxiHPeiWYjeUyvRRhWuNYE,359
15
+ python_omnilogic_local-0.15.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
16
+ python_omnilogic_local-0.15.1.dist-info/METADATA,sha256=qrnrN1w8YOaQiQWHvUyYMMC85LJxMDxgnfDBEHYkaUE,2634
17
+ python_omnilogic_local-0.15.1.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
18
+ python_omnilogic_local-0.15.1.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- pyomnilogic_local/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- pyomnilogic_local/api.py,sha256=3Xdd1ouAcSrSiLvmQnwrJl_3hgRl6KiloBXp0_JDVkE,28134
3
- pyomnilogic_local/cli.py,sha256=RwzKydC612-ay6TGrlSg8UEQPjYIlylxjf11S062bsk,3931
4
- pyomnilogic_local/exceptions.py,sha256=7-EYTP-_VgGrA8WWGwQPUE1NGjJEDWB-ovyvSM2iaNY,164
5
- pyomnilogic_local/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- pyomnilogic_local/models/const.py,sha256=j4HSiPJW5If296yJ-AiIsBI9EdlckF4QkVFIpTLb5C4,51
7
- pyomnilogic_local/models/filter_diagnostics.py,sha256=DnkbjOsmfa39-sbD5qO5PV_Ltn5FHSiImrPBxr7Y0cI,1535
8
- pyomnilogic_local/models/leadmessage.py,sha256=XnzXTpLLQzhLQR1OgfAjKmW5N8BBgM7OrntUi1I2VRY,410
9
- pyomnilogic_local/models/mspconfig.py,sha256=mXfryaHSA8ecJGazpD_4rmrA2vhWtl32_OBmoSCmxGU,10427
10
- pyomnilogic_local/models/telemetry.py,sha256=pBebgBKLClXyLH831GzQdfxbFR7NqyMlktwZzGf1ROg,10632
11
- pyomnilogic_local/models/util.py,sha256=MgqHmDy7OE-62vFX5Rq1tRxs6GmzamBuWoaLYGm-fPI,1479
12
- pyomnilogic_local/protocol.py,sha256=1Z7U70mV0sUlqrp3XK1Fvj6NuChRKLz0ejzKaQLSPE8,10194
13
- pyomnilogic_local/types.py,sha256=km_tagtJ43m4_cIynalis7oiDa1LUUR-ta5B9HQUG1Q,7264
14
- pyomnilogic_local/util.py,sha256=agbRBKnecrYycC9iUmo1aJDjbVg9VxHyq4QY0D8-bfA,359
15
- python_omnilogic_local-0.14.4.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
16
- python_omnilogic_local-0.14.4.dist-info/METADATA,sha256=JxeeJko3UZKJ5tmEDArSQlQFCoIBROIsmmjsM1jha18,2984
17
- python_omnilogic_local-0.14.4.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
18
- python_omnilogic_local-0.14.4.dist-info/entry_points.txt,sha256=PUvdumqSijeB0dHH_s5oE2TnWtPWdJSNpSOsn8yTtOo,56
19
- python_omnilogic_local-0.14.4.dist-info/RECORD,,
@@ -1,3 +0,0 @@
1
- [console_scripts]
2
- omnilogic=pyomnilogic_local.cli:main
3
-