CDP-Client
==========
A simple python interface for the CDP Studio development platform that allows Python scripts to interact with CDP Applications - retrieve CDP Application structures and read-write object values. For more information about CDP Studio see https://cdpstudio.com/
The API makes heavy use of promise library for asynchronous operations. For more information see https://pypi.python.org/pypi/promise
Installation
------------
::
$ pip install cdp-client
Usage
-----
The example below shows how you subscribe to CDP signal value changes.
.. code:: python
from cdp_client import cdp
def on_value_changed(value, timestamp):
print(value)
def subscribe_to_value_changes(node):
node.subscribe_to_value_changes(on_value_changed)
client = cdp.Client(host='127.0.0.1')
client.find_node('AppName.ComponentName.SignalName').then(subscribe_to_value_changes)
client.run_event_loop()
API
---
Before all examples, you need:
.. code:: python
from cdp_client import cdp
Global API
~~~~~~~~~~
Client(host, port, auto_reconnect, notification_listener, encryption_parameters)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Arguments
host - String for hosts ip address
port - Optional port number to connect to. If not specified default port 7689 is used.
auto_reconnect - Optional argument to enable/disable automatic reconnect when connection is lost. Defaults to True if not specified.
notification_listener - NotificationListener object whose methods are called on different connection events (e.g. when server requires credentials)
encryption_parameters - Optional argument to set encryption and its parameters, TLS certificates verification etc. Parameter is compatible with python websocket client 'sslopt' parameter. For more information see https://pypi.org/project/websocket_client
- Returns
The connected client object.
- Usage example
.. code:: python
client = cdp.Client(host='127.0.0.1')
- Usage example with password authentication
.. code:: python
class MyListener(cdp.NotificationListener):
def credentials_requested(self, request):
if request.user_auth_result().code() == cdp.AuthResultCode.CREDENTIALS_REQUIRED:
# Do something to gather username and password variables (either sync or async way) and then call:
request.accept({'Username': 'test', 'Password': '12345678'});
client = cdp.Client(host='127.0.0.1', notification_listener=MyListener())
- Usage example with password authentication and encryption in use, without server certificate verification
.. code:: python
import ssl
class MyListener(cdp.NotificationListener):
def credentials_requested(self, request):
if request.user_auth_result().code() == cdp.AuthResultCode.CREDENTIALS_REQUIRED:
# Do something to gather username and password variables (either sync or async way) and then call:
request.accept({'Username': 'test', 'Password': '12345678'});
client = cdp.Client(host='127.0.0.1', notification_listener=MyListener(),
encryption_parameters={'use_encryption': True, 'cert_reqs': ssl.CERT_NONE})
- Usage example with password authentication and encryption in use, with server certificate verification
.. code:: python
import ssl
class MyListener(cdp.NotificationListener):
def credentials_requested(self, request):
if request.user_auth_result().code() == cdp.AuthResultCode.CREDENTIALS_REQUIRED:
# Do something to gather username and password variables (either sync or async way) and then call:
request.accept({'Username': 'test', 'Password': '12345678'});
client = cdp.Client(host='127.0.0.1', notification_listener=MyListener(),
encryption_parameters={'use_encryption': True,
'cert_reqs': ssl.CERT_REQUIRED,
'ca_certs': 'StudioAPI.crt',
'check_hostname': False},
Instance Methods / Client
~~~~~~~~~~~~~~~~~~~~~~~~~
client.root_node()
^^^^^^^^^^^^^^^^^^
Gets the application Node object of the connected application.
- Returns
Promise containing root Node object when fulfilled.
- Usage
.. code:: python
client.root_node().then(on_success).catch(on_error)
client.find_node(path)
^^^^^^^^^^^^^^^^^^^^^^
Searches for the node specified by full dot separated path. **The requested node must reside in the application client was connected to. Root node is not considered part of the path.**
- Arguments
path - Dot separated string to target node
- Returns
Promise containing requested Node object when fulfilled. Otherwise NotFoundError when rejected.
- Usage
.. code:: python
client.find_node('AppName.ComponentName.SignalName').then(on_success).catch(on_error)
client.run_event_loop()
^^^^^^^^^^^^^^^^^^^^^^^
Runs the event loop that serves network communication layer for incoming/outgoing data. **This is a blocking call that must be run for any communication to happen.** The method can be cancelled by calling disconnect.
client.disconnect()
^^^^^^^^^^^^^^^^^^^
Stops the event loop and closes the connection to connected application. This method also releases the blocking run_event_loop call.
Instance Methods / Node
~~~~~~~~~~~~~~~~~~~~~~~
node.name()
^^^^^^^^^^^
- Returns
The name of the Node object. Names in a parent node are all unique.
node.path()
^^^^^^^^^^^
- Returns
A dot separated path of the Node object starting with application name.
node.parent()
^^^^^^^^^^^^^
- Returns
The parent Node object.
node.type()
^^^^^^^^^^^
- Returns
The type of the Node object returned as one of the cdp.NodeType values.
node.class_name()
^^^^^^^^^^^^^^^^^
- Returns
CDP class name as a string.
node.last_value()
^^^^^^^^^^^^^^^^^
- Returns
The last known value received by the Node object.
node.set_value(value, timestamp)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Sets a new value for the Node object. Timestamp will be ignored in current implementation.
- Arguments
value - New value
timestamp - UTC time in nanoseconds since Epoch
node.is_read_only()
^^^^^^^^^^^^^^^^^^^
- Returns
False if nodes value cannot be set, otherwise True.
node.is_leaf()
^^^^^^^^^^^^^^
- Returns
True if node doesn't have any children, otherwise False.
node.child(name)
^^^^^^^^^^^^^^^^
- Arguments
name - Child nodes name to search for
- Returns
Promise containing requested Node object when fulfilled.
- Usage
.. code:: python
node.child('NodeName').then(on_success).catch(on_error)
node.children()
^^^^^^^^^^^^^^^
- Returns
Promise containing all children of this Node object when fulfilled.
- Usage
.. code:: python
node.children().then(on_success).catch(on_error)
node.for_each_child(callback)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Loops through all children and calls callback function for each of them
- Arguments
callback - Function(node)
- Returns
Promise containing all children of this Node object when fulfilled.
- Usage
.. code:: python
def on_callback(child):
do something
node.for_each_child(on_callback)
node.subscribe_to_structure_changes(callback)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Starts listening structure changes and passes the changes to provided callback funtion
- Arguments
callback - Function(added_nodes, removed_nodes) where added_nodes and removed_nodes is a list
- Usage
.. code:: python
def on_change(added_nodes, removed_nodes):
do something
node.subscribe_to_structure_changes(on_change)
node.subscribe_to_value_changes(callback, fs=5, sample_rate=0)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Starts listening value changes and passes the changes to provided callback function
- Arguments
callback - Function(value, timestamp)
fs - Maximum frequency that value updates are expected (controls how many changes are sent in a single packet). Defaults to 5 hz.
sample_rate - Maximum amount of value updates sent per second (controls the amount of data transferred). Zero means all samples must be provided. Defaults to 0.
- Usage
.. code:: python
def on_change(value, timestamp):
do something
node.subscribe_to_value_changes(on_change)
node.unsubscribe_from_structure_changes(callback)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Stops listening previously subscribed structure changes
- Arguments
callback - Function(added_nodes, removed_nodes) where added_nodes and removed_nodes is a list
- Usage
.. code:: python
def on_change(added_nodes, removed_nodes):
do something
node.unsubscribe_from_structure_changes(on_change)
node.unsubscribe_from_value_changes(callback)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Stops listening previously subscribed value changes
- Arguments
callback - Function(value, timestamp)
- Usage
.. code:: python
def on_change(value, timestamp):
do something
node.unsubscribe_from_value_changes(on_change)
Notification Listener
~~~~~~~~~~~~~~~~~~~~~
To handle different connection events (like prompt user to accept a system use notification message or request user to enter credentials for authentication or idle lockout re-authentication) a notification_listener parameter must be provided to the Client.
The notification_listener parameter must be a object of type class cdp.NotificationListener.
class NotificationListener
^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code:: python
class NotificationListener:
def application_acceptance_requested(self, request=AuthRequest()):
request.accept()
def credentials_requested(self, request=AuthRequest()):
raise NotImplementedError("NotificationListener credentials_requested() not implemented!")
NotificationListener.application_acceptance_requested(self, request=AuthRequest())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Called by Client when new application TLS or plain TCP connection is established.
Can be used to prompt the user a System Use Notification (a message that can be configured in CDP Studio Security settings).
- Arguments
request - a object that has method accept() that should be called to accept the connection and a reject() to reject the connection.
- Usage
.. code:: python
class MyListener(cdp.NotificationListener):
def application_acceptance_requested(self, request):
if request.system_use_notification():
# Pop up a System Use Notification message and ask for confirmation to continue,
# then based on the user answer call either request.accept() or request.reject()
else:
request.accept()
client = cdp.Client(host='127.0.0.1', port=7689, notification_listener=MyListener())
NotificationListener.credentials_requested(self, request=AuthRequest())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Called by Client when server is requesting credentials (authentication or idle lockout re-authentication).
- Arguments
request - a object that has method accept(data=dict()) that should be called (with credentials) for authentication try, and also a method reject() to reject the connection.
- Usage
.. code:: python
class MyListener(cdp.NotificationListener):
def credentials_requested(self, request):
if request.user_auth_result().code() == cdp.AuthResultCode.CREDENTIALS_REQUIRED:
# Do something to gather username and password variables (either sync or async way) and then call:
request.accept({'Username': 'test', 'Password': '12345678'});
if request.user_auth_result().code() == cdp.AuthResultCode.REAUTHENTICATION_REQUIRED:
# Pop user a message that idle lockout was happened and server requires new authentication to continue:
request.accept({'Username': 'test', 'Password': '12345678'});
client = cdp.Client(host='127.0.0.1', port=7689, notification_listener=MyListener())
Tests
-----
To run the test suite execute the following command in package root folder:
.. code:: sh
$ python setup.py test
License
-------
`MIT
License <https://github.com/CDPTechnologies/PythonCDPClient/blob/master/LICENSE.txt>`__
Raw data
{
"_id": null,
"home_page": "https://github.com/CDPTechnologies/PythonCDPClient",
"name": "cdp-client",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "cdp cdpstudio studio client cdp-client cdp_client",
"author": "CDP Technologies AS",
"author_email": "info@cdptech.com",
"download_url": "https://files.pythonhosted.org/packages/6e/25/c6f3dce796ab89a327d63365b44b489514623f5fff91b5289dfc3980afe3/cdp_client-2.2.2.tar.gz",
"platform": null,
"description": "CDP-Client\n==========\n\nA simple python interface for the CDP Studio development platform that allows Python scripts to interact with CDP Applications - retrieve CDP Application structures and read-write object values. For more information about CDP Studio see https://cdpstudio.com/\n\nThe API makes heavy use of promise library for asynchronous operations. For more information see https://pypi.python.org/pypi/promise\n\nInstallation\n------------\n\n::\n\n $ pip install cdp-client\n\nUsage\n-----\n\nThe example below shows how you subscribe to CDP signal value changes.\n\n.. code:: python\n\n from cdp_client import cdp\n\n def on_value_changed(value, timestamp):\n print(value)\n\t\n def subscribe_to_value_changes(node):\n node.subscribe_to_value_changes(on_value_changed)\n\t\n client = cdp.Client(host='127.0.0.1')\n client.find_node('AppName.ComponentName.SignalName').then(subscribe_to_value_changes)\n client.run_event_loop()\n\nAPI\n---\n\nBefore all examples, you need:\n\n.. code:: python\n\n from cdp_client import cdp\n\nGlobal API\n~~~~~~~~~~\n\nClient(host, port, auto_reconnect, notification_listener, encryption_parameters)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n- Arguments\n\n host - String for hosts ip address\n\n port - Optional port number to connect to. If not specified default port 7689 is used.\n\n auto_reconnect - Optional argument to enable/disable automatic reconnect when connection is lost. Defaults to True if not specified.\n\n notification_listener - NotificationListener object whose methods are called on different connection events (e.g. when server requires credentials)\n\n encryption_parameters - Optional argument to set encryption and its parameters, TLS certificates verification etc. Parameter is compatible with python websocket client 'sslopt' parameter. For more information see https://pypi.org/project/websocket_client\n\n- Returns\n\n The connected client object.\n\n- Usage example\n\n .. code:: python\n\n client = cdp.Client(host='127.0.0.1')\n\n- Usage example with password authentication\n\n .. code:: python\n\n class MyListener(cdp.NotificationListener):\n def credentials_requested(self, request):\n if request.user_auth_result().code() == cdp.AuthResultCode.CREDENTIALS_REQUIRED:\n # Do something to gather username and password variables (either sync or async way) and then call:\n request.accept({'Username': 'test', 'Password': '12345678'});\n\n client = cdp.Client(host='127.0.0.1', notification_listener=MyListener())\n\n- Usage example with password authentication and encryption in use, without server certificate verification\n\n .. code:: python\n\n import ssl\n\n class MyListener(cdp.NotificationListener):\n def credentials_requested(self, request):\n if request.user_auth_result().code() == cdp.AuthResultCode.CREDENTIALS_REQUIRED:\n # Do something to gather username and password variables (either sync or async way) and then call:\n request.accept({'Username': 'test', 'Password': '12345678'});\n\n client = cdp.Client(host='127.0.0.1', notification_listener=MyListener(),\n encryption_parameters={'use_encryption': True, 'cert_reqs': ssl.CERT_NONE})\n\n\n- Usage example with password authentication and encryption in use, with server certificate verification\n\n .. code:: python\n\n import ssl\n\n class MyListener(cdp.NotificationListener):\n def credentials_requested(self, request):\n if request.user_auth_result().code() == cdp.AuthResultCode.CREDENTIALS_REQUIRED:\n # Do something to gather username and password variables (either sync or async way) and then call:\n request.accept({'Username': 'test', 'Password': '12345678'});\n\n client = cdp.Client(host='127.0.0.1', notification_listener=MyListener(),\n encryption_parameters={'use_encryption': True,\n 'cert_reqs': ssl.CERT_REQUIRED,\n 'ca_certs': 'StudioAPI.crt',\n 'check_hostname': False},\n\nInstance Methods / Client\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\nclient.root_node()\n^^^^^^^^^^^^^^^^^^\n\nGets the application Node object of the connected application.\n\n- Returns\n\n Promise containing root Node object when fulfilled.\n\n- Usage\n\n .. code:: python\n\n client.root_node().then(on_success).catch(on_error)\n\nclient.find_node(path)\n^^^^^^^^^^^^^^^^^^^^^^\n\nSearches for the node specified by full dot separated path. **The requested node must reside in the application client was connected to. Root node is not considered part of the path.**\n\n- Arguments\n\n path - Dot separated string to target node\n\n- Returns\n\n Promise containing requested Node object when fulfilled. Otherwise NotFoundError when rejected.\n\n- Usage\n\n .. code:: python\n\n client.find_node('AppName.ComponentName.SignalName').then(on_success).catch(on_error)\n\nclient.run_event_loop()\n^^^^^^^^^^^^^^^^^^^^^^^\n\nRuns the event loop that serves network communication layer for incoming/outgoing data. **This is a blocking call that must be run for any communication to happen.** The method can be cancelled by calling disconnect.\n\nclient.disconnect()\n^^^^^^^^^^^^^^^^^^^\n\nStops the event loop and closes the connection to connected application. This method also releases the blocking run_event_loop call.\n\nInstance Methods / Node\n~~~~~~~~~~~~~~~~~~~~~~~\n\nnode.name()\n^^^^^^^^^^^\n\n- Returns\n\n The name of the Node object. Names in a parent node are all unique.\n\nnode.path()\n^^^^^^^^^^^\n\n- Returns\n\n A dot separated path of the Node object starting with application name.\n\nnode.parent()\n^^^^^^^^^^^^^\n\n- Returns\n\n The parent Node object.\n\nnode.type()\n^^^^^^^^^^^\n\n- Returns\n\n The type of the Node object returned as one of the cdp.NodeType values.\n\nnode.class_name()\n^^^^^^^^^^^^^^^^^\n\n- Returns\n\n CDP class name as a string.\n\nnode.last_value()\n^^^^^^^^^^^^^^^^^\n\n- Returns\n\n The last known value received by the Node object.\n\nnode.set_value(value, timestamp)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nSets a new value for the Node object. Timestamp will be ignored in current implementation.\n\n- Arguments\n\n value - New value\n\n timestamp - UTC time in nanoseconds since Epoch\n\nnode.is_read_only()\n^^^^^^^^^^^^^^^^^^^\n\n- Returns\n\n False if nodes value cannot be set, otherwise True.\n\nnode.is_leaf()\n^^^^^^^^^^^^^^\n\n- Returns\n\n True if node doesn't have any children, otherwise False.\n\nnode.child(name)\n^^^^^^^^^^^^^^^^\n\n- Arguments\n\n name - Child nodes name to search for\n\n- Returns\n\n Promise containing requested Node object when fulfilled.\n\n- Usage\n\n .. code:: python\n\n node.child('NodeName').then(on_success).catch(on_error)\n\nnode.children()\n^^^^^^^^^^^^^^^\n\n- Returns\n\n Promise containing all children of this Node object when fulfilled.\n\n- Usage\n\n .. code:: python\n\n node.children().then(on_success).catch(on_error)\n\nnode.for_each_child(callback)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nLoops through all children and calls callback function for each of them\n\n- Arguments\n\n callback - Function(node)\n\n- Returns\n\n Promise containing all children of this Node object when fulfilled.\n\n- Usage\n\n .. code:: python\n\n def on_callback(child):\n do something\n\n node.for_each_child(on_callback)\n\nnode.subscribe_to_structure_changes(callback)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nStarts listening structure changes and passes the changes to provided callback funtion\n\n- Arguments\n\n callback - Function(added_nodes, removed_nodes) where added_nodes and removed_nodes is a list\n\n- Usage\n\n .. code:: python\n\n def on_change(added_nodes, removed_nodes):\n do something\n\n node.subscribe_to_structure_changes(on_change)\n\nnode.subscribe_to_value_changes(callback, fs=5, sample_rate=0)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nStarts listening value changes and passes the changes to provided callback function\n\n- Arguments\n\n callback - Function(value, timestamp)\n\n fs - Maximum frequency that value updates are expected (controls how many changes are sent in a single packet). Defaults to 5 hz.\n \n sample_rate - Maximum amount of value updates sent per second (controls the amount of data transferred). Zero means all samples must be provided. Defaults to 0.\n\n- Usage\n\n .. code:: python\n\n def on_change(value, timestamp):\n do something\n\n node.subscribe_to_value_changes(on_change)\n\n\nnode.unsubscribe_from_structure_changes(callback)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nStops listening previously subscribed structure changes\n\n- Arguments\n\n callback - Function(added_nodes, removed_nodes) where added_nodes and removed_nodes is a list\n\n- Usage\n\n .. code:: python\n\n def on_change(added_nodes, removed_nodes):\n do something\n\n node.unsubscribe_from_structure_changes(on_change)\n\nnode.unsubscribe_from_value_changes(callback)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nStops listening previously subscribed value changes\n\n- Arguments\n\n callback - Function(value, timestamp)\n\n- Usage\n\n .. code:: python\n\n def on_change(value, timestamp):\n do something\n\t\n node.unsubscribe_from_value_changes(on_change)\n\nNotification Listener\n~~~~~~~~~~~~~~~~~~~~~\n\nTo handle different connection events (like prompt user to accept a system use notification message or request user to enter credentials for authentication or idle lockout re-authentication) a notification_listener parameter must be provided to the Client.\nThe notification_listener parameter must be a object of type class cdp.NotificationListener.\n\nclass NotificationListener\n^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n .. code:: python\n\n class NotificationListener:\n def application_acceptance_requested(self, request=AuthRequest()):\n request.accept()\n\n def credentials_requested(self, request=AuthRequest()):\n raise NotImplementedError(\"NotificationListener credentials_requested() not implemented!\")\n\nNotificationListener.application_acceptance_requested(self, request=AuthRequest())\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nCalled by Client when new application TLS or plain TCP connection is established.\nCan be used to prompt the user a System Use Notification (a message that can be configured in CDP Studio Security settings).\n\n- Arguments\n\n request - a object that has method accept() that should be called to accept the connection and a reject() to reject the connection.\n\n- Usage\n\n .. code:: python\n\n class MyListener(cdp.NotificationListener):\n def application_acceptance_requested(self, request):\n if request.system_use_notification():\n # Pop up a System Use Notification message and ask for confirmation to continue,\n # then based on the user answer call either request.accept() or request.reject()\n else:\n request.accept()\n\n client = cdp.Client(host='127.0.0.1', port=7689, notification_listener=MyListener())\n\nNotificationListener.credentials_requested(self, request=AuthRequest())\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nCalled by Client when server is requesting credentials (authentication or idle lockout re-authentication).\n\n- Arguments\n\n request - a object that has method accept(data=dict()) that should be called (with credentials) for authentication try, and also a method reject() to reject the connection.\n\n- Usage\n\n .. code:: python\n\n class MyListener(cdp.NotificationListener):\n def credentials_requested(self, request):\n if request.user_auth_result().code() == cdp.AuthResultCode.CREDENTIALS_REQUIRED:\n # Do something to gather username and password variables (either sync or async way) and then call:\n request.accept({'Username': 'test', 'Password': '12345678'});\n if request.user_auth_result().code() == cdp.AuthResultCode.REAUTHENTICATION_REQUIRED:\n # Pop user a message that idle lockout was happened and server requires new authentication to continue:\n request.accept({'Username': 'test', 'Password': '12345678'});\n\n client = cdp.Client(host='127.0.0.1', port=7689, notification_listener=MyListener())\n\nTests\n-----\n\nTo run the test suite execute the following command in package root folder:\n\n.. code:: sh\n\n $ python setup.py test\n\nLicense\n-------\n\n`MIT\nLicense <https://github.com/CDPTechnologies/PythonCDPClient/blob/master/LICENSE.txt>`__\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Provides an API that allows to interact with CDP applications",
"version": "2.2.2",
"project_urls": {
"Homepage": "https://github.com/CDPTechnologies/PythonCDPClient"
},
"split_keywords": [
"cdp",
"cdpstudio",
"studio",
"client",
"cdp-client",
"cdp_client"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "15cc38a5b51bfcb6ce40d791cb44e2ec8383c430dc84cab25336ee41c84aec5b",
"md5": "53a6b0e37c4f2ac337e8b8bd19240532",
"sha256": "92f5d122666f5f6137181d256462f03be426eb363349d3c0b6dc766c3f0c69d1"
},
"downloads": -1,
"filename": "cdp_client-2.2.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "53a6b0e37c4f2ac337e8b8bd19240532",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 26409,
"upload_time": "2024-07-03T11:28:05",
"upload_time_iso_8601": "2024-07-03T11:28:05.278669Z",
"url": "https://files.pythonhosted.org/packages/15/cc/38a5b51bfcb6ce40d791cb44e2ec8383c430dc84cab25336ee41c84aec5b/cdp_client-2.2.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "6e25c6f3dce796ab89a327d63365b44b489514623f5fff91b5289dfc3980afe3",
"md5": "189dfa2eef02e9b228514751d2707c21",
"sha256": "67982950ef8989344526ee2750e62cd6d9868c2693faa4922bc268a1b35ebf70"
},
"downloads": -1,
"filename": "cdp_client-2.2.2.tar.gz",
"has_sig": false,
"md5_digest": "189dfa2eef02e9b228514751d2707c21",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 26715,
"upload_time": "2024-07-03T11:28:07",
"upload_time_iso_8601": "2024-07-03T11:28:07.427501Z",
"url": "https://files.pythonhosted.org/packages/6e/25/c6f3dce796ab89a327d63365b44b489514623f5fff91b5289dfc3980afe3/cdp_client-2.2.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-07-03 11:28:07",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "CDPTechnologies",
"github_project": "PythonCDPClient",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "cdp-client"
}