Skip to content

Commit c9e6054

Browse files
committed
Version 0.4 to support SSL and other improvements.
1 parent 6a7d67e commit c9e6054

6 files changed

Lines changed: 384 additions & 85 deletions

File tree

CHANGES

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
osdf-python 0.4
2+
3+
* Supports SSL encrypted connections to secured OSDF instances.
4+
* Added method for complete schema retrieval for a namespace.
5+
* Able to retrieve previous version of node documents.
6+
* Improved README documentation.
7+
* More tests.
8+
9+
- Victor <victor73@github.com> Mon, 07 Mar 2016 16:00:00 -0400
10+
111
osdf-python 0.3.1
212

313
* Added missing LICENSE file.

README.md

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
# osdf-python
44

5+
## Basic usage
6+
57
import pprint
68
from osdf import OSDF
79

@@ -15,3 +17,135 @@
1517
info = osdf.get_info()
1618

1719
pprint.pprint(info)
20+
21+
22+
## SSL/Encrypted connections
23+
24+
To establish a connection to an instance of OSDF that is encrypted by
25+
operating with an SSL certificate, simply pass the a named ssl parameter
26+
set to true.
27+
28+
osdf = OSDF(server, username, password, port, ssl=True)
29+
30+
## Obtaining the server information
31+
32+
info = osdf.get_info()
33+
34+
pprint.pprint(info)
35+
36+
{
37+
"api_version": "0.1",
38+
"title": "EXAMPLE-OSDF",
39+
"description": "Open Science Data Framework (OSDF)",
40+
"admin_contact_email1": "osdf-admin@example.edu",
41+
"admin_contact_email2": "help@example.edu",
42+
"technical_contact1": "osdf@example.edu",
43+
"technical_contact2": "osdf-helpdesk@example.edu",
44+
"comment1": "comment1",
45+
"comment2": "comment2"
46+
}
47+
48+
## Retrieve an existing node
49+
One is able to retrieve a node by ID easily.
50+
51+
node = osdf.get_node(node_id)
52+
53+
## Retrieve a previous version of an existing node
54+
OSDF maintains the history of nodes as they change over time
55+
from edit to edit. To retrieve a particular node at a specific
56+
version number, simply pass the versoin number (as well as the node
57+
id of interest) to the get_node_by_version() function.
58+
59+
node = osdf.get_node_by_version(node_id, version)
60+
61+
## Validate a node document
62+
Sometimes its useful to check if a document validates against the OSDF instance
63+
to verify if the metadata in the document passes all the structural integrity
64+
and other requirements. To validate a document, use the validate_node()
65+
function, and pass the JSON data as an argument. The return is a tuple with the
66+
first value containing a boolean with the result of the validation, and the
67+
second value will contain the error message (if the document was not valid).
68+
69+
(is_valid, error) = osdf.validate_node(json_data)
70+
71+
## Inserting a node
72+
The creation/insertion of a new node returns the node's ID.
73+
74+
document = {
75+
"ns": "test",
76+
"acl": { "read": [ "all" ], "write": [ "all" ] },
77+
"linkage": {},
78+
"node_type": "example",
79+
"meta": {
80+
"description": "something",
81+
"color": "blue"
82+
}
83+
}
84+
85+
node_id = osdf.insert_node(document)
86+
87+
## Edit/Update a node
88+
Updates an existing node document with new/edited data. OSDF will save the
89+
older data to the node's history, and it will be available for retrieval
90+
by version number. The provided node data must contain the node ID as well
91+
as the current version number of the node, so as to avoid conflicts with others
92+
that may be attempting to edit that document.
93+
94+
osdf.edit_node(node_data)
95+
96+
## Deleting a node
97+
To delete a node, simply call the delete_node() function. This action also
98+
removes the historical information associated with that node (previous
99+
versions).
100+
101+
osdf.delete_node(node_id)
102+
103+
## ElasticSearch DSL queries
104+
namespace = "test"
105+
query = '{ "query": { "term": { "node_type": "example" }} }'
106+
first_page_results = osdf.query(namespace, query)
107+
# If there are more than 1 "page" of results, additional results
108+
# can be obtained...
109+
second_page_results = osdf.query(namespace, query, 2)
110+
111+
To retrieve ALL results by aggregating all the available pages of results
112+
113+
all_results = osdf.query_all_pages(namespace, query)
114+
115+
## OQL (OSDF Query Language) queries
116+
OSDF also supports a simplified query language called OQL (OSDF Query Language). To issue
117+
an OQL query:
118+
119+
namespace = "test"
120+
query = '"example"[node_type]'
121+
first_page_results = osdf.oql_query(namespace, query, 1)
122+
# If there are more than 1 "page" of results, additional results
123+
# can be obtained...
124+
second_page_results = osdf.oql_query(namespace, query, 2)
125+
126+
To retrieve ALL results by aggregating all the available pages of results
127+
128+
all_results = osdf.oql_query_all_pages(namespace, query)
129+
130+
## Retrieve all schemas for a given namespace
131+
Namespaces can impose controls on the JSON data contained in their nodes according
132+
to the nodetype. To retrieve the complete set of registered schemas for a particular
133+
namespace, use the get_schemas() function:
134+
135+
schemas = osdf.get_schemas(namespace)
136+
137+
## Retrieve a specific schema
138+
If a node type has a JSON-Schema associated with it, that specific schema
139+
can be queried from OSDF using the get_schema() function by passing the name of
140+
namespace as well as the name of the schema/node_type.
141+
142+
schema = osdf.get_schema(namespace, schema_name)
143+
144+
## Retrieve an OSDF auxiliary schema
145+
Schemas can share JSON-Schema fragments between them in order to avoid duplication.
146+
These schema fragements are referred to as auxiliary schemas, and are also
147+
retrievable with the get_aux_schema() function by passing the namespace and
148+
auxiliary schema name.
149+
150+
aux_schema = osdf.get_aux_schema(namespace, aux_schema_name)
151+

osdf.py

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,18 @@ class OSDF(object):
1313
operations (node creation, deletion, queries, etc.)
1414
"""
1515

16-
def __init__(self, server, username, password, port=8123):
16+
def __init__(self, server, username, password, port=8123, ssl=False):
1717
self._server = server
1818
self._port = port
1919
self._username = username
2020
self._password = password
21-
self._request = HttpRequest(server, username, password, port=port)
21+
self._ssl = ssl
22+
self._set_request()
23+
24+
def _set_request(self):
25+
self._request = HttpRequest(self._server, self._username,
26+
self._password, self._port,
27+
self._ssl)
2228

2329
@property
2430
def server(self):
@@ -28,8 +34,7 @@ def server(self):
2834
def server(self, server):
2935
self._server = server
3036
# Redefine the request object
31-
self._request = HttpRequest(self._server, self._username,
32-
self._password, self._port)
37+
self._set_request()
3338

3439
@property
3540
def port(self):
@@ -39,8 +44,7 @@ def port(self):
3944
def port(self, port):
4045
self._port = port
4146
# Redefine the request object
42-
self._request = HttpRequest(self._server, self._username,
43-
self._password, self._port)
47+
self._set_request()
4448

4549
@property
4650
def username(self):
@@ -50,8 +54,7 @@ def username(self):
5054
def username(self, username):
5155
self._username = username
5256
# Redefine the request object
53-
self._request = HttpRequest(self._server, self._username,
54-
self._password, self._port)
57+
self._set_request()
5558

5659
@property
5760
def password(self):
@@ -61,8 +64,20 @@ def password(self):
6164
def password(self, password):
6265
self._password = password
6366
# Redefine the request object
64-
self._request = HttpRequest(self._server, self._username,
65-
self._password, self._port)
67+
self._set_request()
68+
69+
@property
70+
def ssl(self):
71+
return self._ssl
72+
73+
@ssl.setter
74+
def ssl(self, ssl):
75+
if type(ssl) is not bool:
76+
raise ValueError("Invalid value for ssl.")
77+
78+
self._ssl = ssl
79+
# Redefine the request object
80+
self._set_request()
6681

6782
def edit_node(self, json_data):
6883
"""
@@ -122,6 +137,43 @@ def get_node(self, node_id):
122137

123138
return data
124139

140+
def get_node_by_version(self, node_id, version):
141+
"""
142+
Given a numerical version number, retrieves an OSDF node's data
143+
as it was at that version.
144+
145+
Returns the parsed form of the JSON document for the node
146+
"""
147+
osdf_response = self._request.get("/nodes/%s/ver/%s", (node_id, version))
148+
149+
if osdf_response["code"] != 200:
150+
headers = osdf_response['headers']
151+
self.header_error(headers, 'retrieve', 'node')
152+
153+
data = json.loads( osdf_response['content'] )
154+
155+
data = self._byteify(data)
156+
157+
return data
158+
159+
def get_schemas(self, namespace):
160+
"""
161+
Retrieves all of the schemas for a particular namespace.
162+
"""
163+
url = '/namespaces/%s/schemas/' % namespace
164+
165+
osdf_response = self._request.get(url)
166+
167+
if osdf_response["code"] != 200:
168+
headers = osdf_response['headers']
169+
self.header_error(headers, 'retrieve', 'schemas')
170+
171+
all_schema_data = json.loads( osdf_response['content'] )
172+
173+
schema_data = self._byteify(all_schema_data)
174+
175+
return all_schema_data
176+
125177
def get_schema(self, namespace, schema_name):
126178
"""
127179
Retrieves a namespace's document schema
@@ -154,7 +206,7 @@ def get_aux_schema(self, namespace, aux_schema_name):
154206

155207
if osdf_response["code"] != 200:
156208
headers = osdf_response['headers']
157-
self.header_error(headers, 'retrieve', 'schema')
209+
self.header_error(headers, 'retrieve', 'aux schema')
158210

159211
aux_schema_data = json.loads( osdf_response['content'] )
160212

request.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,23 @@ def __str__(self):
1414

1515
class HttpRequest(object):
1616

17-
def __init__(self, server, username, password, port=8123):
17+
def __init__(self, server, username, password, port=8123, ssl=False):
1818
self.server = server
1919
self.port = port
2020
self.username = username
2121
self.password = password
22+
self.ssl = ssl
23+
24+
def _get_connection(self):
25+
if (self.ssl):
26+
conn = httplib.HTTPSConnection(self.server, self.port)
27+
else:
28+
conn = httplib.HTTPConnection(self.server, self.port)
29+
30+
return conn
2231

2332
def delete(self, resource):
24-
conn = httplib.HTTPConnection(self.server, self.port)
33+
conn = self._get_connection()
2534

2635
conn.putrequest("DELETE", resource)
2736
self._set_auth_header(conn)
@@ -45,7 +54,7 @@ def delete(self, resource):
4554
return results
4655

4756
def get(self, resource):
48-
conn = httplib.HTTPConnection(self.server, self.port)
57+
conn = self._get_connection()
4958
conn.putrequest("GET", resource)
5059
self._set_auth_header(conn)
5160
conn.endheaders()
@@ -68,7 +77,7 @@ def get(self, resource):
6877
return results
6978

7079
def put(self, resource, data):
71-
conn = httplib.HTTPConnection(self.server, self.port, True)
80+
conn = self._get_connection()
7281
conn.putrequest("PUT", resource)
7382
self._set_auth_header(conn)
7483
conn.putheader("Content-Length", "%d" % len(data))
@@ -95,7 +104,7 @@ def put(self, resource, data):
95104
return results
96105

97106
def post(self, resource, data):
98-
conn = httplib.HTTPConnection(self.server, self.port, True)
107+
conn = self._get_connection()
99108

100109
conn.putrequest("POST", resource)
101110
self._set_auth_header(conn)

setup.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,14 @@ def read(fname):
77

88
setup(name='osdf-python',
99
description='Python client to Open Science Data Framework (OSDF) REST servers.',
10-
long_description=read('README.md'),
11-
version='0.3.1',
10+
long_description='The Open Science Data Framework (OSDF) is a specialized ' + \
11+
'document database that allows users to store, retrieve, ' + \
12+
'query and track changes to data over time easily. ' + \
13+
'Because the API uses JSON and REST, developers are ' + \
14+
'able to use OSDF in the language of their choice ' + \
15+
'because almost every language has support for ' + \
16+
'communications via HTTP and working with JSON.'
17+
version='0.4',
1218
py_modules=['osdf', 'request'],
1319
author='Victor Felix',
1420
author_email='victor73@github.com',

0 commit comments

Comments
 (0)