Skip to content

Commit 1d4c923

Browse files
author
Paul Osborne
committed
PYTHONDC-1: Initial sphinx documentation support and reworking APIs
1 parent 1444f1f commit 1d4c923

13 files changed

Lines changed: 1297 additions & 286 deletions

File tree

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,7 @@ cover
5454
#-------------------------------------------------------------------------------
5555
# Sphinx build files
5656
#-------------------------------------------------------------------------------
57-
build/docs/Makefile
58-
build/docs/make.bat
57+
docs/_build/
5958

6059
#-------------------------------------------------------------------------------
6160
# Application builds

devicecloud/__init__.py

Lines changed: 90 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
from devicecloud.api.sci import ServerCommandInterfaceAPI
1+
import json
22

33
__version__ = "0.1"
44

5-
from devicecloud.api.devicecore import DeviceCoreAPI
65
from requests.auth import HTTPBasicAuth
7-
from api.filedata import FileDataAPI
8-
from api.streams import StreamAPI
96
import logging
107
import requests
118
import time
@@ -21,9 +18,6 @@
2118
201
2219
]
2320

24-
PING_URL = "/ws/DeviceCore?size=1"
25-
ONE_DAY = 86400 # in seconds
26-
2721
logger = logging.getLogger("dc")
2822

2923

@@ -33,22 +27,24 @@ class DeviceCloudException(Exception):
3327

3428
class DeviceCloudHttpException(DeviceCloudException):
3529
"""Exception raised when we failed a request to the DC over HTTP"""
30+
3631
def __init__(self, response, *args, **kwargs):
3732
DeviceCloudException.__init__(self, *args, **kwargs)
3833
self.response = response
3934

4035

4136
class _DeviceCloudConnection(object):
37+
"""Encapsulate information about a connection to the device cloud
38+
39+
This class is used internally and does not represent a part of the public API
40+
to the device cloud.
41+
42+
"""
43+
4244
def __init__(self, auth, base_url):
4345
self._auth = auth
4446
self._base_url = base_url
4547

46-
def connect(self):
47-
"""Establish/Verify a connection with the Device Cloud"""
48-
49-
# Ping the device cloud, raises exception if it fails
50-
self.ping()
51-
5248
def _make_url(self, path):
5349
if not path.startswith("/"):
5450
path = "/" + path
@@ -67,13 +63,25 @@ def _make_request(self, retries, method, url, **kwargs):
6763
raise DeviceCloudHttpException(response, err)
6864

6965
def ping(self):
70-
"""Ping the Device Cloud using the authorization provided"""
71-
self.get(PING_URL) # TODO: Is this sufficient, valid?
66+
"""Ping the Device Cloud using the authorization provided
67+
68+
:returns: The response of getting a single device from DeviceCore on success
69+
:raises: :class:`.DeviceCloudHttpException` if there is a problem
70+
71+
"""
72+
return self.get("/ws/DeviceCore?size=1")
7273

7374
def get(self, path, retries=0, **kwargs):
7475
url = self._make_url(path)
7576
return self._make_request(retries, "GET", url, **kwargs)
7677

78+
def get_json(self, path, retries=0, **kwargs):
79+
url = self._make_url(path)
80+
headers = kwargs.setdefault('headers', {})
81+
headers.update({'Accept': 'application/json'})
82+
response = self._make_request(retries, "GET", url, **kwargs)
83+
return json.loads(response.text)
84+
7785
def post(self, path, data, retries=0, **kwargs):
7886
url = self._make_url(path)
7987
return self._make_request(retries, "POST", url, data=data, **kwargs)
@@ -88,91 +96,80 @@ def delete(self, path, retries=0):
8896

8997

9098
class DeviceCloud(object):
91-
"""Provides access to information/operations on a device cloud account"""
99+
"""Provide access to core device cloud features
100+
101+
This class is the primary interface to the device cloud through which access to individual
102+
device cloud services is provided. Creating a ``DeviceCloud`` object is as easy as doing
103+
the following::
104+
105+
from devicecloud import DeviceCloud
106+
107+
dc = DeviceCloud('user', 'pass')
108+
if dc.has_valid_credentials():
109+
devicecore = dc.get_devicecore_api()
110+
print devicecore.list_devices()
111+
112+
From there, access to all of the device clouds features are possible. In some cases, methods
113+
for quickly performing selected actions may be provided directly via the ``DeviceCloud`` object
114+
while advanced usage requires using functionality exposed through other interfaces.
115+
116+
"""
92117

93118
def __init__(self, username, password, base_url="https://login.etherios.com"):
94119
self._conn = _DeviceCloudConnection(HTTPBasicAuth(username, password), base_url)
95-
self._conn.connect()
96-
97-
# API Components
98-
self._file_data = FileDataAPI(self._conn)
99-
self._streams = StreamAPI(self._conn)
100-
self._sci = ServerCommandInterfaceAPI(self._conn)
101-
self._device_core = DeviceCoreAPI(self._conn, self._sci)
102-
103-
#---------------------------------------------------------------------------
104-
# API - Streams
105-
#---------------------------------------------------------------------------
106-
def create_data_stream(self, name, data_type, description=None,
107-
data_ttl=(ONE_DAY * 2),
108-
rollup_ttl=(ONE_DAY * 5)):
109-
"""Create and return a DataStream object from the Device Cloud
110-
111-
TODO: Describe the usage of `data_ttl` and `rollup_ttl`
120+
121+
def has_valid_credentials(self):
122+
"""Verify that the device cloud url, username, and password are valid
123+
124+
This method will attempt to "ping" the device cloud in order to ensure that all
125+
of the provided information is correct.
126+
127+
:returns: True if the credentials are valid and false if not
128+
112129
"""
113-
return self._streams.create_data_stream(name, data_type, description,
114-
data_ttl, rollup_ttl)
115-
116-
def get_available_streams(self, cached=False):
117-
"""Return a list of all available streams"""
118-
return self._streams.get_streams(cached)
119-
120-
def get_stream(self, stream_id, cached=False):
121-
return self._streams.get_stream(stream_id, cached)
122-
123-
def stream_write(self, stream_id, data):
124-
"""Write a DataPoint to a previously opened DataStream"""
125-
self._streams.stream_write(stream_id, data)
126-
127-
def stream_read(self, stream_id):
128-
"""Return data from some stream"""
129-
return self._streams.stream_read(stream_id)
130-
131-
#---------------------------------------------------------------------------
132-
# API - FileData
133-
#---------------------------------------------------------------------------
134-
def get_filedata_file(self, file_glob, device=None, from_date=None, contents=False):
135-
"""Gets files that match the *file_glob* pattern using the FileData API
136-
137-
If *device* is not ``None`` then it will only look for files from *device*.
138-
If *from_date* is not ``None`` then it will only for files modified since
139-
*from_date*. If *include_contents* is ``True`` then the file contents
140-
will be retrieved.
130+
try:
131+
self._conn.ping()
132+
except DeviceCloudException:
133+
return False
134+
else:
135+
return True
136+
137+
def get_streams_api(self):
138+
"""Returns a :class:`.StreamAPI` bound to this device cloud instance
139+
140+
:returns: :class:`.StreamAPI` object bound to this device cloud account
141+
141142
"""
142-
return self._file_data.get_files(file_glob, device, from_date, contents)
143+
from devicecloud.api.streams import StreamAPI
143144

144-
def put_filedata_file(self, file_name, file_data):
145-
self._file_data.put_file(file_name, file_data)
145+
return StreamAPI(self._conn)
146146

147-
#---------------------------------------------------------------------------
148-
# API - DeviceCore
149-
#---------------------------------------------------------------------------
150-
def list_devices(self):
151-
"""Get information about all devices associated with this device cloud account
147+
def get_filedata_api(self):
148+
"""Returns a :class:`.FileDataAPI` bound to this device cloud instance
152149
153-
This method will return a list of :class:`.Device` instances. Additional operations
154-
can be performed on these instances.
150+
:returns: :class:`.FileDataAPI` bound to this device cloud account
155151
156152
"""
157-
return self._device_core.list_devices()
158-
159-
#---------------------------------------------------------------------------
160-
# API - Devices (SCI)
161-
#---------------------------------------------------------------------------
162-
def sci_put_file(self, addr, file_name, file_data):
163-
"""Put a file onto the filesystem of a connected device"""
164-
raise NotImplementedError()
165-
166-
def sci_get_file(self, addr, glob):
167-
"""Get a file from the filesystem of a connected device"""
168-
raise NotImplementedError()
169-
170-
#---------------------------------------------------------------------------
171-
# API - Monitors
172-
#---------------------------------------------------------------------------
173-
# TODO: Implement me
174-
175-
#---------------------------------------------------------------------------
176-
# API - Alarms
177-
#---------------------------------------------------------------------------
178-
# TODO: Implement me
153+
from devicecloud.api.filedata import FileDataAPI # prevent circular imports
154+
155+
return FileDataAPI(self._conn)
156+
157+
def get_devicecore_api(self):
158+
"""Returns a :class:`.DeviceCoreAPI` bound to this device cloud instance
159+
160+
:returns: :class:`.DeviceCoreAPI` bound to this device cloud account
161+
162+
"""
163+
from devicecloud.api.devicecore import DeviceCoreAPI
164+
165+
return DeviceCoreAPI(self._conn, self.get_sci_api())
166+
167+
def get_sci_api(self):
168+
"""Returns a :class:`.ServerCommandInterfaceAPI` bound to this device cloud instance
169+
170+
:returns: :class:`.ServerCommandInterfaceAPI` bound to this device cloud account
171+
172+
"""
173+
from devicecloud.api.sci import ServerCommandInterfaceAPI
174+
175+
return ServerCommandInterfaceAPI(self._conn)

0 commit comments

Comments
 (0)