python-omnilogic-local 0.14.4__py3-none-any.whl → 0.15.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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
-