naeural-client 2.0.3__py3-none-any.whl → 2.1.0__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.
@@ -11,3 +11,5 @@ from .base_decentra_object import BaseDecentrAIObject
11
11
  from .plugins_manager_mixin import _PluginsManagerMixin
12
12
  from .logging import Logger
13
13
  from .code_cheker import BaseCodeChecker
14
+ from .const import PLUGIN_SIGNATURES
15
+ from .default.instance import PLUGIN_TYPES
naeural_client/_ver.py CHANGED
@@ -1,4 +1,4 @@
1
- __VER__ = "2.0.3"
1
+ __VER__ = "2.1.0"
2
2
 
3
3
  if __name__ == "__main__":
4
4
  with open("pyproject.toml", "rt") as fd:
@@ -9,7 +9,7 @@ from time import time as tm
9
9
 
10
10
  from ..base_decentra_object import BaseDecentrAIObject
11
11
  from ..bc import DefaultBlockEngine
12
- from ..const import COMMANDS, ENVIRONMENT, HB, PAYLOAD_DATA, STATUS_TYPE
12
+ from ..const import COMMANDS, ENVIRONMENT, HB, PAYLOAD_DATA, STATUS_TYPE, PLUGIN_SIGNATURES
13
13
  from ..const import comms as comm_ct
14
14
  from ..io_formatter import IOFormatterWrapper
15
15
  from ..logging import Logger
@@ -1396,7 +1396,7 @@ class GenericSession(BaseDecentrAIObject):
1396
1396
  def create_or_attach_to_pipeline(self, *,
1397
1397
  node,
1398
1398
  name,
1399
- data_source,
1399
+ data_source="Void",
1400
1400
  config={},
1401
1401
  plugins=[],
1402
1402
  on_data=None,
@@ -1410,15 +1410,21 @@ class GenericSession(BaseDecentrAIObject):
1410
1410
  ----------
1411
1411
  node : str
1412
1412
  Address or Name of the Naeural Edge Protocol edge node that will handle this pipeline.
1413
+
1413
1414
  name : str
1414
1415
  Name of the pipeline. This is good to be kept unique, as it allows multiple parties to overwrite each others configurations.
1416
+
1415
1417
  data_source : str
1416
1418
  This is the name of the DCT plugin, which resembles the desired functionality of the acquisition.
1419
+ Defaults to "Void" - no actual data acquisition.
1420
+
1417
1421
  config : dict, optional
1418
1422
  This is the dictionary that contains the configuration of the acquisition source, by default {}
1423
+
1419
1424
  plugins : list
1420
1425
  List of dictionaries which contain the configurations of each plugin instance that is desired to run on the box.
1421
1426
  Defaults to []. Should be left [], and instances should be created with the api.
1427
+
1422
1428
  on_data : Callable[[Pipeline, str, str, dict], None], optional
1423
1429
  Callback that handles messages received from any plugin instance.
1424
1430
  As arguments, it has a reference to this Pipeline object, the signature and the instance of the plugin
@@ -1426,15 +1432,18 @@ class GenericSession(BaseDecentrAIObject):
1426
1432
  This callback acts as a default payload processor and will be called even if for a given instance
1427
1433
  the user has defined a specific callback.
1428
1434
  Defaults to None.
1435
+
1429
1436
  on_notification : Callable[[Pipeline, dict], None], optional
1430
1437
  Callback that handles notifications received from any plugin instance.
1431
1438
  As arguments, it has a reference to this Pipeline object, along with the payload itself.
1432
1439
  This callback acts as a default payload processor and will be called even if for a given instance
1433
1440
  the user has defined a specific callback.
1434
1441
  Defaults to None.
1442
+
1435
1443
  max_wait_time : int, optional
1436
1444
  The maximum time to busy-wait, allowing the Session object to listen to node heartbeats
1437
1445
  and to check if the desired node is online in the network, by default 0.
1446
+
1438
1447
  **kwargs :
1439
1448
  The user can provide the configuration of the acquisition source directly as kwargs.
1440
1449
 
@@ -1651,15 +1660,39 @@ class GenericSession(BaseDecentrAIObject):
1651
1660
  *,
1652
1661
  node,
1653
1662
  name,
1654
- signature="CUSTOM_CODE_FASTAPI_01",
1663
+ signature=PLUGIN_SIGNATURES.CUSTOM_WEB_APP_01,
1655
1664
  endpoints=None,
1656
1665
  use_ngrok=True,
1657
1666
  **kwargs
1658
1667
  ):
1668
+ """
1669
+ Create a new web app on a node.
1670
+
1671
+ Parameters
1672
+ ----------
1673
+
1674
+ node : str
1675
+ Address or Name of the Naeural Edge Protocol edge node that will handle this web app.
1676
+
1677
+ name : str
1678
+ Name of the web app.
1679
+
1680
+ signature : str, optional
1681
+ The signature of the plugin that will be used. Defaults to PLUGIN_SIGNATURES.CUSTOM_WEB_APP_01.
1682
+
1683
+ endpoints : list[dict], optional
1684
+ A list of dictionaries defining the endpoint configuration. Defaults to None.
1685
+
1686
+ use_ngrok : bool, optional
1687
+ If True, will use ngrok to expose the web app. Defaults to True.
1688
+
1689
+
1690
+ """
1659
1691
 
1660
1692
  pipeline: Pipeline = self.create_pipeline(
1661
1693
  node=node,
1662
1694
  name=name,
1695
+ # default TYPE is "Void"
1663
1696
  )
1664
1697
 
1665
1698
  instance = pipeline.create_plugin_instance(
@@ -1677,6 +1710,43 @@ class GenericSession(BaseDecentrAIObject):
1677
1710
  # end if we have endpoints defined in the call
1678
1711
 
1679
1712
  return pipeline, instance
1713
+
1714
+
1715
+ def create_telegram_simple_bot(
1716
+ self,
1717
+ *,
1718
+ node,
1719
+ name,
1720
+ signature=PLUGIN_SIGNATURES.CUSTOM_WEB_APP_01,
1721
+ message_handler=None,
1722
+ telegram_bot_token=None,
1723
+ telegram_bot_token_env_key=ENVIRONMENT.TELEGRAM_BOT_TOKEN_ENV_KEY,
1724
+ **kwargs
1725
+ ):
1726
+
1727
+ if telegram_bot_token is None:
1728
+ telegram_bot_token = os.getenv(telegram_bot_token_env_key)
1729
+ if telegram_bot_token is None:
1730
+ message = f"Warning! No Telegram bot token provided as via env {ENVIRONMENT.TELEGRAM_BOT_TOKEN_ENV_KEY} or explicitly as `telegram_bot_token` param."
1731
+ raise ValueError(message)
1732
+
1733
+ b64code = self._get_base64_code(message_handler)
1734
+
1735
+ pipeline: Pipeline = self.create_pipeline(
1736
+ node=node,
1737
+ name=name,
1738
+ # default TYPE is "Void"
1739
+ )
1740
+
1741
+ instance = pipeline.create_plugin_instance(
1742
+ signature=signature,
1743
+ instance_id=self.log.get_unique_id(),
1744
+ telegram_bot_token=telegram_bot_token,
1745
+ message_handler=b64code,
1746
+ **kwargs
1747
+ )
1748
+ return pipeline, instance
1749
+
1680
1750
 
1681
1751
  def broadcast_instance_command_and_wait_for_response_payload(
1682
1752
  self,
@@ -7,3 +7,4 @@ from .payload import STATUS_TYPE, PAYLOAD_DATA, COMMANDS, NOTIFICATION_CODES
7
7
  from .base import CONFIG_STREAM, BIZ_PLUGIN_DATA, PLUGIN_INFO
8
8
  from . import heartbeat as HB
9
9
  from .environment import ENVIRONMENT
10
+ from .apps import PLUGIN_SIGNATURES
@@ -0,0 +1,11 @@
1
+ class PLUGIN_SIGNATURES:
2
+ """
3
+ This class is used to store the plugin signatures for the different plugins.
4
+ It is complementary to the PLUGIN_TYPES class.
5
+ """
6
+ NET_MON_01 = 'NET_MON_01'
7
+ VIEW_SCENE_01 = 'VIEW_SCENE_01'
8
+ CUSTOM_WEB_APP_01 = 'CUSTOM_CODE_FASTAPI_01'
9
+ CHAIN_DIST_CUSTOM_JOB_01 = 'PROCESS_REAL_TIME_COLLECTED_DATA_CUSTOM_EXEC_CHAIN_DIST'
10
+ BASIC_TELEGRAM_BOT_01 = 'BASIC_TELEGRAM_BOT_01'
11
+ # INSERT_NEW_PLUGIN_HERE
@@ -28,3 +28,5 @@ class ENVIRONMENT:
28
28
 
29
29
  EE_SECURED = 'EE_SECURED'
30
30
  AIXP_SECURED = 'AIXP_SECURED'
31
+
32
+ TELEGRAM_BOT_TOKEN_ENV_KEY = 'TELEGRAM_BOT_TOKEN'
@@ -2,3 +2,15 @@ from .net_mon_01_plugin import NetMon01
2
2
  from .view_scene_01_plugin import ViewScene01
3
3
  from .custom_web_app_01_plugin import CustomWebApp01
4
4
  from .chain_dist_custom_job_01_plugin import ChainDistCustomJob01
5
+ from .basic_telegram_bot_01_plugin import BasicTelegramBot01
6
+
7
+
8
+ class PLUGIN_TYPES:
9
+ """
10
+ The plugin types that are available in the default instance
11
+ """
12
+ NET_MON_01 = NetMon01
13
+ VIEW_SCENE_01 = ViewScene01
14
+ CUSTOM_WEB_APP_01 = CustomWebApp01
15
+ CHAIN_DIST_CUSTOM_JOB_01 = ChainDistCustomJob01
16
+ BASIC_TELEGRAM_BOT_01 = BasicTelegramBot01
@@ -0,0 +1,5 @@
1
+ from ...base import Instance
2
+ from ...const import PLUGIN_SIGNATURES
3
+
4
+ class BasicTelegramBot01(Instance):
5
+ signature = PLUGIN_SIGNATURES.BASIC_TELEGRAM_BOT_01
@@ -1,8 +1,9 @@
1
1
  from ...base import Instance
2
+ from ...const import PLUGIN_SIGNATURES
2
3
 
3
4
 
4
5
  class ChainDistCustomJob01(Instance):
5
- signature = "PROCESS_REAL_TIME_COLLECTED_DATA_CUSTOM_EXEC_CHAIN_DIST"
6
+ signature = PLUGIN_SIGNATURES.CHAIN_DIST_CUSTOM_JOB_01
6
7
 
7
8
  def add_custom_code_callbacks(
8
9
  self,
@@ -1,8 +1,8 @@
1
1
  from ...base import Instance, Pipeline
2
-
2
+ from ...const import PLUGIN_SIGNATURES
3
3
 
4
4
  class CustomWebApp01(Instance):
5
- signature = "CUSTOM_CODE_FASTAPI_01"
5
+ signature = PLUGIN_SIGNATURES.CUSTOM_WEB_APP_01
6
6
 
7
7
  def get_proposed_endpoints(self):
8
8
  from copy import deepcopy
@@ -1,8 +1,8 @@
1
1
  from ...base import Instance
2
-
2
+ from ...const import PLUGIN_SIGNATURES
3
3
 
4
4
  class NetMon01(Instance):
5
- signature = "NET_MON_01"
5
+ signature = PLUGIN_SIGNATURES.NET_MON_01
6
6
 
7
7
  def get_node_history(self, node_id=None, node_addr=None, time_window_hours=1, steps=20):
8
8
  """
@@ -1,8 +1,8 @@
1
1
  from ...base import Instance
2
-
2
+ from ...const import PLUGIN_SIGNATURES
3
3
 
4
4
  class ViewScene01(Instance):
5
- signature = "VIEW_SCENE_01"
5
+ signature = PLUGIN_SIGNATURES.VIEW_SCENE_01
6
6
 
7
7
  def get_last_witness(self, response_params_key="COMMAND_PARAMS"):
8
8
  """
@@ -180,11 +180,12 @@ class BaseLogger(object):
180
180
  if lib_ver == "":
181
181
  lib_ver = __VER__
182
182
  ver = "v{}".format(lib_ver) if lib_ver != "" else ""
183
- self.verbose_log(
184
- "SDK [{} {}] initialized on machine [{}][{}].".format(
185
- self.__lib__, ver, self.MACHINE_NAME, self.get_processor_platform(),
183
+ self.P(
184
+ "NSDK {} initialized on [{}][{}].".format(
185
+ ver, self.MACHINE_NAME, self.get_processor_platform(),
186
186
  ),
187
- color='green'
187
+ color='green',
188
+ boxed=True,
188
189
  )
189
190
  self.verbose_log(" Timezone: {}.".format(self.timezone),color='green')
190
191
 
@@ -1,11 +1,10 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: naeural_client
3
- Version: 2.0.3
3
+ Version: 2.1.0
4
4
  Summary: `naeural_client` is the Python SDK required for client app development for the Naeural Edge Protocol Edge Protocol framework
5
5
  Project-URL: Homepage, https://github.com/Naeural Edge ProtocolEdgeProtocol/naeural_client
6
6
  Project-URL: Bug Tracker, https://github.com/Naeural Edge ProtocolEdgeProtocol/naeural_client/issues
7
7
  Author-email: Stefan Saraev <saraevstefan@gmail.com>, Andrei Ionut Damian <andrei.damian@me.com>, Cristan Bleotiu <cristibleotiu@gmail.com>
8
- License-File: LICENSE
9
8
  Classifier: License :: OSI Approved :: MIT License
10
9
  Classifier: Operating System :: OS Independent
11
10
  Classifier: Programming Language :: Python :: 3
@@ -1,10 +1,10 @@
1
- naeural_client/__init__.py,sha256=ZNoadMrxrd1EZqxni0zpoqjFIBrS8Jg-vfZrr7xwe9I,498
2
- naeural_client/_ver.py,sha256=22NfIkgjJksCD3HVuCZFvbFPyAMVCrB4W2uIX0hfSRw,330
1
+ naeural_client/__init__.py,sha256=UKEDGS0wFYyxwmhEAKJGecO2vYbIfRYUP4SQgnK10IE,578
2
+ naeural_client/_ver.py,sha256=PKIJgoKWB4wskSQA9KvdwJkGx2b-A3tKTo2Rq6DMhdw,330
3
3
  naeural_client/base_decentra_object.py,sha256=qDBpitcyhr1eEXPD8cGFtcNPNf71fqNRsmOEcCpx4sM,4180
4
4
  naeural_client/plugins_manager_mixin.py,sha256=X1JdGLDz0gN1rPnTN_5mJXR8JmqoBFQISJXmPR9yvCo,11106
5
5
  naeural_client/base/__init__.py,sha256=hACh83_cIv7-PwYMM3bQm2IBmNqiHw-3PAfDfAEKz9A,259
6
6
  naeural_client/base/distributed_custom_code_presets.py,sha256=cvz5R88P6Z5V61Ce1vHVVh8bOkgXd6gve_vdESDNAsg,2544
7
- naeural_client/base/generic_session.py,sha256=QEuXQVB3bCPk4CfrFVOwUHER1S6RzxH332GNgXvV3J4,67207
7
+ naeural_client/base/generic_session.py,sha256=azhJGCXstzBFQjWqW1z5OjwtSn2nkoPCNsSIcag5hIE,69231
8
8
  naeural_client/base/instance.py,sha256=m6IKOWuT5GsZVSdFNdcR-ImJTpTdHqNoMe8KQlEK3Gc,19970
9
9
  naeural_client/base/pipeline.py,sha256=fWwSNUvvrVvJYzxRBCKTt1f9_pci1hCBiG2LtoyOpMU,57512
10
10
  naeural_client/base/plugin_template.py,sha256=qGaXByd_JZFpjvH9GXNbT7KaitRxIJB6-1IhbKrZjq4,138123
@@ -25,20 +25,22 @@ naeural_client/comm/__init__.py,sha256=za3B2HUKNXzYtjElMgGM9xbxNsdQfFY4JB_YzdyFk
25
25
  naeural_client/comm/amqp_wrapper.py,sha256=hzj6ih07DnLQy2VSfA88giDIFHaCp9uSdGLTA-IFE4s,8535
26
26
  naeural_client/comm/mqtt_wrapper.py,sha256=Ig3bFZkCbWd4y_Whn2PPa91Z3aLgNbNPau6Tn5yLPZ8,16167
27
27
  naeural_client/const/README.md,sha256=6OHesr-f5NBuuJGryEoi_TCu2XdlhfQYlDKx_IJoXeg,177
28
- naeural_client/const/__init__.py,sha256=nm0maDn_l44UQkJy4XLHnOcpHMypkVvYYDFkezi6_rk,380
28
+ naeural_client/const/__init__.py,sha256=G7Fa50SpEhAPOnL8_mxgVmJ0Xq1qEncWd75pg2BkiG4,416
29
+ naeural_client/const/apps.py,sha256=i0MNCM1Wf7QUCB4OKO1vGNUonPs6EsnZV6-XZjknppw,439
29
30
  naeural_client/const/base.py,sha256=V94oaT7xYrrTGxmLJlynxmbFujVX0G9wIfC8TilH5MU,2548
30
31
  naeural_client/const/comms.py,sha256=La6JXWHexH8CfcBCKyT4fCIoeaoZlcm7KtZ57ab4ZgU,2201
31
- naeural_client/const/environment.py,sha256=Aj_AyelP_Y97CgEM6pvIv2T9TLbe7sT2mrkg6OtGShg,698
32
+ naeural_client/const/environment.py,sha256=bq21Q7e5FXpTNpoek_CUOX5oOZpSJEtNHXiZ79ZHe18,753
32
33
  naeural_client/const/formatter.py,sha256=AW3bWlqf39uaqV4BBUuW95qKYfF2OkkU4f9hy3kSVhM,200
33
34
  naeural_client/const/heartbeat.py,sha256=jGHmKfeHTFOXJaKUT3o_ocnQyF-EpcLeunW-ifkYKfU,2534
34
35
  naeural_client/const/misc.py,sha256=1ypROmZsOyp_8zG2LARwPeo-YfXuyYqZnml0elTP4kw,211
35
36
  naeural_client/const/payload.py,sha256=k24vH9iJIBBPnCXx7HAEuli2fNAETK7h8ZuVKyKLgbk,5725
36
37
  naeural_client/default/__init__.py,sha256=ozU6CMMuWl0LhG8Ae3LrZ65a6tLrptfscVYGf83zjxM,46
37
- naeural_client/default/instance/__init__.py,sha256=k1YZhbhLh7-Q7avnvwuQ2Ij-BhGbTlgwiWsOj9cS9xU,205
38
- naeural_client/default/instance/chain_dist_custom_job_01_plugin.py,sha256=-YO26dH3774wkMbj0Z0GACpVeVYblkxV4KhidtPEqcI,1891
39
- naeural_client/default/instance/custom_web_app_01_plugin.py,sha256=9swEcfEzpL_P29WDkP9kTZ8oHNS0s9TXwd5BfIGiDZI,4805
40
- naeural_client/default/instance/net_mon_01_plugin.py,sha256=1k1Ul6pKyhSfAYbcfj38t404Z3KyMVvfhlMJdzIgV-c,1154
41
- naeural_client/default/instance/view_scene_01_plugin.py,sha256=bQtkQKrZRvzenlH3JYVvBXe2Tow5qdKYlmuvjpBLYn4,666
38
+ naeural_client/default/instance/__init__.py,sha256=pHR9_5t3xv9ug3nu-8202yW-rqq-KR3C_L5N2xaADTA,548
39
+ naeural_client/default/instance/basic_telegram_bot_01_plugin.py,sha256=STaIwtGCnEZdvxm7cF9NIQeZL5Zlru1c4cMSHKJc5pQ,159
40
+ naeural_client/default/instance/chain_dist_custom_job_01_plugin.py,sha256=QtHi3uXKsVs9eyMgbnvBVbMylErhV1Du4X2-7zDL7Y0,1915
41
+ naeural_client/default/instance/custom_web_app_01_plugin.py,sha256=JblmfDa8ICppHItzEqU2HBSgT0nzZy9NWzgUHQ2sffw,4854
42
+ naeural_client/default/instance/net_mon_01_plugin.py,sha256=u85i2AiYHkLJnam0wOx-m71hlp0EYyNtk3JwbkOrvHg,1208
43
+ naeural_client/default/instance/view_scene_01_plugin.py,sha256=5kMhd23kL5AYCdOJzrdCqi2ohoQNvmpv8oE6hWQtUWk,720
42
44
  naeural_client/default/session/mqtt_session.py,sha256=dpQcBhhVZDo458v0IqJMZb1CsTn-TxXhYjNlyJp9Rp8,2414
43
45
  naeural_client/io_formatter/__init__.py,sha256=_wy7c-Z9kgb26jN7uNTDq88G7xZ3wI_ObuQd3QWNPkQ,85
44
46
  naeural_client/io_formatter/io_formatter_manager.py,sha256=MiZ70cGVD6hR99QiEk9wvJ_vADxpI-y2bTb0ITlMNI0,3451
@@ -49,7 +51,7 @@ naeural_client/io_formatter/default/a_dummy.py,sha256=qr9eUizQ-NN5jdXVzkaZKMaf9K
49
51
  naeural_client/io_formatter/default/aixp1.py,sha256=MX0TeUR4APA-qN3vUC6uzcz8Pssz5lgrQWo7td5Ri1A,3052
50
52
  naeural_client/io_formatter/default/default.py,sha256=gEy78cP2D5s0y8vQh4aHuxqz7D10gGfuiKF311QhrpE,494
51
53
  naeural_client/logging/__init__.py,sha256=b79X45VC6c37u32flKB2GAK9f-RR0ocwP0JDCy0t7QQ,33
52
- naeural_client/logging/base_logger.py,sha256=9FflGeC0m3zzcQB2QrRH0iebQn37FDe9r9BxNaoH1J0,65163
54
+ naeural_client/logging/base_logger.py,sha256=tTxzCKOhcqGOtckHK8lQ1nUTNeaBNkeh0_SmDyzX6_Y,65146
53
55
  naeural_client/logging/small_logger.py,sha256=6wljiHP1moCkgohRnr2EX095eM2RtdJ5B3cytbO_Ow4,2887
54
56
  naeural_client/logging/logger_mixins/__init__.py,sha256=yQO7umlRvz63FeWpi-F9GRmC_MOHcNW6R6pwvZZBy3A,600
55
57
  naeural_client/logging/logger_mixins/class_instance_mixin.py,sha256=xUXE2VZgmrlrSrvw0f6GF1jlTnVLeVkIiG0bhlBfq3o,2741
@@ -72,7 +74,7 @@ naeural_client/logging/tzlocal/windows_tz.py,sha256=Sv9okktjZJfRGGUOOppsvQuX_eXy
72
74
  naeural_client/utils/__init__.py,sha256=mAnke3-MeRzz3nhQvhuHqLnpaaCSmDxicd7Ck9uwpmI,77
73
75
  naeural_client/utils/comm_utils.py,sha256=4cS9llRr_pK_3rNgDcRMCQwYPO0kcNU7AdWy_LtMyCY,1072
74
76
  naeural_client/utils/dotenv.py,sha256=_AgSo35n7EnQv5yDyu7C7i0kHragLJoCGydHjvOkrYY,2008
75
- naeural_client-2.0.3.dist-info/METADATA,sha256=5ONsD3fdCiVEh4Z3_h8bOkcbwz0RqBwCi0gP6YKzU5M,14479
76
- naeural_client-2.0.3.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
77
- naeural_client-2.0.3.dist-info/licenses/LICENSE,sha256=cvOsJVslde4oIaTCadabXnPqZmzcBO2f2zwXZRmJEbE,11311
78
- naeural_client-2.0.3.dist-info/RECORD,,
77
+ naeural_client-2.1.0.dist-info/METADATA,sha256=I71wSC0lZI0XDuh8j1mIcyHoxL8Y5SNcB0d_K31BTP0,14457
78
+ naeural_client-2.1.0.dist-info/WHEEL,sha256=wukiCwsxxsuzcQTdnC_ZWHZECE4wwOh3xCCrap6i6Ts,87
79
+ naeural_client-2.1.0.dist-info/licenses/LICENSE,sha256=cvOsJVslde4oIaTCadabXnPqZmzcBO2f2zwXZRmJEbE,11311
80
+ naeural_client-2.1.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.25.0
2
+ Generator: hatchling 1.26.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any