Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 556fb8c

Browse files
committedMar 15, 2016
Merge pull request #2 from LabKey/fb_stability
Stability
2 parents 5201ada + d23e9f5 commit 556fb8c

File tree

6 files changed

+86
-35
lines changed

6 files changed

+86
-35
lines changed
 

‎README.md

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
1-
# About
2-
The Python client API for LabKey Server lets you query, insert and update data on a LabKey Server from a Python client.
1+
Python API for LabKey Server. Lets you query, insert, and update data on a LabKey Server using Python.
32

4-
# Release Notes
3+
## Release Notes
54

65
Changes in the current release:
76

87
- Support for Python 3
9-
- Support for netrc files (.labkeycredentials.txt files are now deprecated)
8+
- Use netrc files for credentials -- see [Credentials](#credentials)
109
- New methods for working with assay data:
1110
- [load_batch](./labkey/experiment.py)
1211
- [save_batch](./labkey/experiment.py)
1312
- server_context parameter added to all methods
1413
- PEP standards - the latest version follows PEP code styling standards
1514
- New [samples](./samples)
1615

17-
# Installation
16+
## Installation
1817
To install, simply use `pip`:
1918

2019
```bash
@@ -23,10 +22,10 @@ $ pip install labkey
2322

2423
**Note:** For users who installed this package before it was published to PyPI (before v0.3.0) it is recommended you uninstall and reinstall the package rather than attempting to upgrade. This is due to a change in the package's versioning semantics.
2524

26-
# Credentials
25+
## Credentials
2726
As of v0.4.0 this API no longer supports using a ``.labkeycredentials.txt`` file, and now uses the .netrc files similar to the other labkey APIs. Additional .netrc [setup instructions](https://www.labkey.org/wiki/home/Documentation/page.view?name=netrc) can be found at the link.
2827

29-
## Set Up a netrc File
28+
### Set Up a netrc File
3029

3130
On a Mac, UNIX, or Linux system the netrc file should be named ``.netrc`` (dot netrc) and on Windows it should be named ``_netrc`` (underscore netrc). The file should be located in your home directory and the permissions on the file must be set so that you are the only user who can read it, i.e. it is unreadable to everyone else.
3231

@@ -49,7 +48,7 @@ password mypassword
4948
```
5049
Note that the netrc file only deals with connections at the machine level and should not include a port or protocol designation, meaning both "mymachine.labkey.org:8888" and "https://mymachine.labkey.org" are incorrect.
5150

52-
# Supported Functions
51+
## Supported Functions
5352

5453
- **labkey.query.select_rows()** - Query and get results sets from LabKey Server.
5554
- **labkey.query.execute_sql()** - Execute SQL (LabKey SQL dialect) through the query module on LabKey Server.
@@ -59,7 +58,7 @@ Note that the netrc file only deals with connections at the machine level and sh
5958
- **labkey.experiment.load_batch()** - Retreive assay data (batch level) from LabKey Server.
6059
- **labkey.experiment.save_batch()** - Save assay data (batch level) on LabKey Server.
6160

62-
# Examples
61+
## Examples
6362

6463
Sample code is available in the [samples](https://github.com/LabKey/labkey-api-python/tree/experiment/samples) directory.
6564

@@ -86,9 +85,22 @@ else:
8685
print('select_rows: Failed to load results from ' + schema + '.' + table)
8786
```
8887

89-
# Supported Versions
88+
## Supported Versions
9089
Python 2.6+ and 3.4+ are fully supported.
9190
LabKey Server v13.3 and later.
9291

93-
# Contributing
94-
This library and the LabKey Server are maintained by the LabKey Software Foundation. If you have any questions or need support, please use the [LabKey Server support forum](https://www.labkey.org/wiki/home/page.view?name=support).
92+
## Contributing
93+
This library and the LabKey Server are maintained by the LabKey Software Foundation. If you have any questions or need support, please use the [LabKey Server support forum](https://www.labkey.org/wiki/home/page.view?name=support
94+
95+
### Testing
96+
If you are looking to contribute please run the tests before issuing a PR. For now you need to manually get the dependencies:
97+
98+
```bash
99+
$ pip install mock
100+
```
101+
102+
Then, to run the tests:
103+
104+
```bash
105+
$ python test/test_labkey.py
106+
```

‎labkey/exceptions.py

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,41 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
from requests import exceptions
16+
from requests import exceptions, Response
1717

1818

1919
# base exception class for server responses
2020
class RequestError(exceptions.HTTPError):
2121
default_msg = 'Server Error'
2222

23-
def __init__(self, server_response=None):
24-
if server_response is not None:
23+
def __init__(self, server_response, **kwargs):
24+
"""
25+
:type server_response: Response
26+
"""
27+
super(RequestError, self).__init__(**kwargs)
28+
29+
# base class allows for kwargs 'request' and 'response'
30+
self.response = server_response
31+
self.server_exception = None
32+
33+
if self.response is not None:
34+
msg = self.default_msg
2535
try:
26-
decoded = server_response.json()
36+
decoded = self.response.json()
2737
if 'exception' in decoded:
2838
# use labkey server error message if available
2939
msg = decoded['exception']
3040
self.server_exception = decoded
31-
else:
32-
msg = self.default_msg
3341
except ValueError:
3442
# no valid json to decode
35-
raise ServerNotFoundError(server_response)
43+
pass
3644

37-
self.message = '{0}: {1}'.format(server_response.status_code, msg)
45+
self.message = '{0}: {1}'.format(self.response.status_code, msg)
46+
else:
47+
self.message = 'No response received'
3848

39-
self.response = server_response
49+
def __str__(self):
50+
return repr(self.message)
4051

4152

4253
class QueryNotFoundError(RequestError):
@@ -48,11 +59,7 @@ class RequestAuthorizationError(RequestError):
4859

4960

5061
class ServerNotFoundError(RequestError):
51-
SERVER_NOT_FOUND_MSG = 'Server resource not found. Please verify context path and project path are valid'
52-
53-
def __init__(self, server_response=None):
54-
self.message = '{0}: {1}'.format(server_response.status_code, self.SERVER_NOT_FOUND_MSG)
55-
self.response = server_response
62+
default_msg = 'Server resource not found. Please verify context path and project path are valid'
5663

5764

5865
class ServerContextError(exceptions.HTTPError):

‎labkey/utils.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def build_url(server_context, controller, action, container_path=None):
9898
def handle_response(response):
9999
sc = response.status_code
100100

101-
if sc == 200 or sc == 207:
101+
if (200 <= sc < 300) or sc == 304:
102102
return response.json()
103103
elif sc == 401:
104104
raise RequestAuthorizationError(response)
@@ -112,5 +112,4 @@ def handle_response(response):
112112
else:
113113
raise RequestError(response)
114114

115-
return None
116115

‎test/test_experiment_api.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,15 @@ def test_server_not_found(self):
152152
def test_general_error(self):
153153
test = self
154154
throws_error_test(test, RequestError, self.service.get_general_error_response()
155-
, save_batch, *self.args, **self.expected_kwargs)
155+
, save_batch, *self.args, **self.expected_kwargs)
156+
157+
158+
def suite():
159+
load_tests = unittest.TestLoader().loadTestsFromTestCase
160+
return unittest.TestSuite([
161+
load_tests(TestLoadBatch),
162+
load_tests(TestSaveBatch)
163+
])
164+
165+
if __name__ == '__main__':
166+
unittest.main()

‎test/test_labkey.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from __future__ import unicode_literals
2+
import unittest
3+
4+
from test_experiment_api import suite as exp_suite
5+
from test_query_api import suite as query_suite
6+
7+
if __name__ == '__main__':
8+
all_tests = unittest.TestSuite([
9+
exp_suite(),
10+
query_suite()
11+
])
12+
unittest.TextTestRunner().run(all_tests)

‎test/test_query_api.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def success_test(test, expected_response, api_method, *args, **expected_kwargs):
3333
resp = api_method(*args)
3434

3535
# validate response is as expected
36-
test.assertEquals(resp, expected_response.text)
36+
test.assertEqual(resp, expected_response.text)
3737

3838
# validate call is made as expected
3939
expected_args = expected_kwargs.pop('expected_args')
@@ -72,7 +72,7 @@ def setUp(self):
7272
'expected_args': [self.service.get_server_url()]
7373
, 'data': '{"queryName": "' + query + '", "rows": "{id:1234}", "schemaName": "' + schema + '"}'
7474
, 'headers': {u'Content-Type': u'application/json'}
75-
, 'timeout': 30
75+
, 'timeout': 300
7676
}
7777

7878
rows = '{id:1234}'
@@ -114,7 +114,7 @@ def setUp(self):
114114
'expected_args': [self.service.get_server_url()]
115115
, 'data': '{"queryName": "' + query + '", "rows": "{id:1234}", "schemaName": "' + schema + '"}'
116116
, 'headers': {u'Content-Type': u'application/json'}
117-
, 'timeout': 30
117+
, 'timeout': 300
118118
}
119119

120120
rows = '{id:1234}'
@@ -156,7 +156,7 @@ def setUp(self):
156156
'expected_args': [self.service.get_server_url()]
157157
, 'data': '{"queryName": "' + query + '", "rows": "{id:1234}", "schemaName": "' + schema + '"}'
158158
, 'headers': {u'Content-Type': u'application/json'}
159-
, 'timeout': 30
159+
, 'timeout': 300
160160
}
161161

162162
rows = '{id:1234}'
@@ -199,7 +199,7 @@ def setUp(self):
199199
'expected_args': [self.service.get_server_url()]
200200
, 'data': {'sql': sql, "schemaName": schema}
201201
, 'headers': None
202-
, 'timeout': 30
202+
, 'timeout': 300
203203
}
204204

205205
self.args = [
@@ -240,7 +240,7 @@ def setUp(self):
240240
'expected_args': [self.service.get_server_url()]
241241
, 'data': {"schemaName": schema, "query.queryName": query}
242242
, 'headers': None
243-
, 'timeout': 30
243+
, 'timeout': 300
244244
}
245245

246246
self.args = [
@@ -272,5 +272,15 @@ def test_general_error(self):
272272
, select_rows, *self.args, **self.expected_kwargs)
273273

274274

275+
def suite():
276+
load_tests = unittest.TestLoader().loadTestsFromTestCase
277+
return unittest.TestSuite([
278+
load_tests(TestDeleteRows),
279+
load_tests(TestUpdateRows),
280+
load_tests(TestInsertRows),
281+
load_tests(TestExecuteSQL),
282+
load_tests(TestSelectRows)
283+
])
284+
275285
if __name__ == '__main__':
276286
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.