labkey 2.6.0__py3-none-any.whl → 3.0.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.
labkey/__init__.py CHANGED
@@ -14,6 +14,6 @@
14
14
  # limitations under the License.
15
15
  #
16
16
  __title__ = "labkey"
17
- __version__ = "2.6.0"
17
+ __version__ = "3.0.0"
18
18
  __author__ = "LabKey"
19
19
  __license__ = "Apache License 2.0"
labkey/query.py CHANGED
@@ -44,6 +44,7 @@ import functools
44
44
  from typing import List
45
45
 
46
46
  from .server_context import ServerContext
47
+ from .utils import waf_encode
47
48
 
48
49
  _default_timeout = 60 * 5 # 5 minutes
49
50
 
@@ -164,12 +165,25 @@ class QueryFilter:
164
165
  return "<QueryFilter [{} {} {}]>".format(self.column_name, self.filter_type, self.value)
165
166
 
166
167
 
168
+ class AuditBehavior:
169
+ """
170
+ Enum of different auditing levels
171
+ """
172
+
173
+ DETAILED = "DETAILED"
174
+ NONE = "NONE"
175
+ SUMMARY = "SUMMARY"
176
+
177
+
167
178
  def delete_rows(
168
179
  server_context: ServerContext,
169
180
  schema_name: str,
170
181
  query_name: str,
171
182
  rows: any,
172
183
  container_path: str = None,
184
+ transacted: bool = True,
185
+ audit_behavior: AuditBehavior = None,
186
+ audit_user_comment: str = None,
173
187
  timeout: int = _default_timeout,
174
188
  ):
175
189
  """
@@ -179,12 +193,25 @@ def delete_rows(
179
193
  :param query_name: table name to delete from
180
194
  :param rows: Set of rows to delete
181
195
  :param container_path: labkey container path if not already set in context
196
+ :param transacted: whether all of the updates should be done in a single transaction
197
+ :param audit_behavior: used to override the audit behavior for the update. See class query.AuditBehavior
198
+ :param audit_user_comment: used to provide a comment that will be attached to certain detailed audit log records
182
199
  :param timeout: timeout of request in seconds (defaults to 30s)
183
200
  :return:
184
201
  """
185
202
  url = server_context.build_url("query", "deleteRows.api", container_path=container_path)
203
+
186
204
  payload = {"schemaName": schema_name, "queryName": query_name, "rows": rows}
187
205
 
206
+ if transacted is False:
207
+ payload["transacted"] = transacted
208
+
209
+ if audit_behavior is not None:
210
+ payload["auditBehavior"] = audit_behavior
211
+
212
+ if audit_user_comment is not None:
213
+ payload["auditUserComment"] = audit_user_comment
214
+
188
215
  return server_context.make_request(
189
216
  url,
190
217
  json=payload,
@@ -231,6 +258,7 @@ def execute_sql(
231
258
  parameters: dict = None,
232
259
  required_version: float = None,
233
260
  timeout: int = _default_timeout,
261
+ waf_encode_sql: bool = True
234
262
  ):
235
263
  """
236
264
  Execute sql query against a LabKey server.
@@ -248,11 +276,12 @@ def execute_sql(
248
276
  :param parameters: parameter values to pass through to a parameterized query
249
277
  :param required_version: Api version of response
250
278
  :param timeout: timeout of request in seconds (defaults to 30s)
279
+ :param waf_encode_sql: WAF encode sql in request (defaults to True)
251
280
  :return:
252
281
  """
253
282
  url = server_context.build_url("query", "executeSql.api", container_path=container_path)
254
283
 
255
- payload = {"schemaName": schema_name, "sql": sql}
284
+ payload = {"schemaName": schema_name, "sql": waf_encode(sql) if waf_encode_sql else sql}
256
285
 
257
286
  if container_filter is not None:
258
287
  payload["containerFilter"] = container_filter
@@ -285,6 +314,10 @@ def insert_rows(
285
314
  query_name: str,
286
315
  rows: List[any],
287
316
  container_path: str = None,
317
+ skip_reselect_rows: bool = False,
318
+ transacted: bool = True,
319
+ audit_behavior: AuditBehavior = None,
320
+ audit_user_comment: str = None,
288
321
  timeout: int = _default_timeout,
289
322
  ):
290
323
  """
@@ -294,6 +327,10 @@ def insert_rows(
294
327
  :param query_name: table name to insert into
295
328
  :param rows: set of rows to insert
296
329
  :param container_path: labkey container path if not already set in context
330
+ :param skip_reselect_rows: whether the full detailed response for the insert can be skipped
331
+ :param transacted: whether all of the updates should be done in a single transaction
332
+ :param audit_behavior: used to override the audit behavior for the update. See class query.AuditBehavior
333
+ :param audit_user_comment: used to provide a comment that will be attached to certain detailed audit log records
297
334
  :param timeout: timeout of request in seconds (defaults to 30s)
298
335
  :return:
299
336
  """
@@ -301,6 +338,18 @@ def insert_rows(
301
338
 
302
339
  payload = {"schemaName": schema_name, "queryName": query_name, "rows": rows}
303
340
 
341
+ if skip_reselect_rows is True:
342
+ payload["skipReselectRows"] = skip_reselect_rows
343
+
344
+ if transacted is False:
345
+ payload["transacted"] = transacted
346
+
347
+ if audit_behavior is not None:
348
+ payload["auditBehavior"] = audit_behavior
349
+
350
+ if audit_user_comment is not None:
351
+ payload["auditUserComment"] = audit_user_comment
352
+
304
353
  return server_context.make_request(
305
354
  url,
306
355
  json=payload,
@@ -316,7 +365,7 @@ def select_rows(
316
365
  filter_array: List[QueryFilter] = None,
317
366
  container_path: str = None,
318
367
  columns=None,
319
- max_rows: int = None,
368
+ max_rows: int = -1,
320
369
  sort: str = None,
321
370
  offset: int = None,
322
371
  container_filter: str = None,
@@ -339,7 +388,7 @@ def select_rows(
339
388
  :param filter_array: set of filter objects to apply
340
389
  :param container_path: folder path if not already part of server_context
341
390
  :param columns: set of columns to retrieve
342
- :param max_rows: max number of rows to retrieve
391
+ :param max_rows: max number of rows to retrieve, defaults to -1 (unlimited)
343
392
  :param sort: comma separated list of column names to sort by, prefix a column with '-' to sort descending
344
393
  :param offset: number of rows to offset results by
345
394
  :param container_filter: enumeration of the various container filters available. See:
@@ -419,6 +468,9 @@ def update_rows(
419
468
  query_name: str,
420
469
  rows: List[any],
421
470
  container_path: str = None,
471
+ transacted: bool = True,
472
+ audit_behavior: AuditBehavior = None,
473
+ audit_user_comment: str = None,
422
474
  timeout: int = _default_timeout,
423
475
  ):
424
476
  """
@@ -429,6 +481,9 @@ def update_rows(
429
481
  :param query_name: table name to update
430
482
  :param rows: Set of rows to update
431
483
  :param container_path: labkey container path if not already set in context
484
+ :param transacted: whether all of the updates should be done in a single transaction
485
+ :param audit_behavior: used to override the audit behavior for the update. See class query.AuditBehavior
486
+ :param audit_user_comment: used to provide a comment that will be attached to certain detailed audit log records
432
487
  :param timeout: timeout of request in seconds (defaults to 30s)
433
488
  :return:
434
489
  """
@@ -436,6 +491,61 @@ def update_rows(
436
491
 
437
492
  payload = {"schemaName": schema_name, "queryName": query_name, "rows": rows}
438
493
 
494
+ if transacted is False:
495
+ payload["transacted"] = transacted
496
+
497
+ if audit_behavior is not None:
498
+ payload["auditBehavior"] = audit_behavior
499
+
500
+ if audit_user_comment is not None:
501
+ payload["auditUserComment"] = audit_user_comment
502
+
503
+ return server_context.make_request(
504
+ url,
505
+ json=payload,
506
+ timeout=timeout,
507
+ )
508
+
509
+
510
+ def move_rows(
511
+ server_context: ServerContext,
512
+ target_container_path: str,
513
+ schema_name: str,
514
+ query_name: str,
515
+ rows: any,
516
+ container_path: str = None,
517
+ transacted: bool = True,
518
+ audit_behavior: AuditBehavior = None,
519
+ audit_user_comment: str = None,
520
+ timeout: int = _default_timeout,
521
+ ):
522
+ """
523
+ Move a set of rows from the schema.query
524
+ :param server_context: A LabKey server context. See utils.create_server_context.
525
+ :param target_container_path: target labkey container path for the move
526
+ :param schema_name: schema of table
527
+ :param query_name: table name to move from
528
+ :param rows: Set of rows to move
529
+ :param container_path: source labkey container path if not already set in context
530
+ :param transacted: whether all of the updates should be done in a single transaction
531
+ :param audit_behavior: used to override the audit behavior for the update. See class query.AuditBehavior
532
+ :param audit_user_comment: used to provide a comment that will be attached to certain detailed audit log records
533
+ :param timeout: timeout of request in seconds (defaults to 30s)
534
+ :return:
535
+ """
536
+ url = server_context.build_url("query", "moveRows.api", container_path=container_path)
537
+
538
+ payload = {"targetContainerPath": target_container_path, "schemaName": schema_name, "queryName": query_name, "rows": rows}
539
+
540
+ if transacted is False:
541
+ payload["transacted"] = transacted
542
+
543
+ if audit_behavior is not None:
544
+ payload["auditBehavior"] = audit_behavior
545
+
546
+ if audit_user_comment is not None:
547
+ payload["auditUserComment"] = audit_user_comment
548
+
439
549
  return server_context.make_request(
440
550
  url,
441
551
  json=payload,
@@ -458,10 +568,21 @@ class QueryWrapper:
458
568
  query_name: str,
459
569
  rows: any,
460
570
  container_path: str = None,
571
+ transacted: bool = True,
572
+ audit_behavior: AuditBehavior = None,
573
+ audit_user_comment: str = None,
461
574
  timeout: int = _default_timeout,
462
575
  ):
463
576
  return delete_rows(
464
- self.server_context, schema_name, query_name, rows, container_path, timeout
577
+ self.server_context,
578
+ schema_name,
579
+ query_name,
580
+ rows,
581
+ container_path,
582
+ transacted,
583
+ audit_behavior,
584
+ audit_user_comment,
585
+ timeout
465
586
  )
466
587
 
467
588
  @functools.wraps(truncate_table)
@@ -484,6 +605,7 @@ class QueryWrapper:
484
605
  parameters: dict = None,
485
606
  required_version: float = None,
486
607
  timeout: int = _default_timeout,
608
+ waf_encode_sql: bool = True
487
609
  ):
488
610
  return execute_sql(
489
611
  self.server_context,
@@ -498,6 +620,7 @@ class QueryWrapper:
498
620
  parameters,
499
621
  required_version,
500
622
  timeout,
623
+ waf_encode_sql
501
624
  )
502
625
 
503
626
  @functools.wraps(insert_rows)
@@ -507,10 +630,23 @@ class QueryWrapper:
507
630
  query_name: str,
508
631
  rows: List[any],
509
632
  container_path: str = None,
633
+ skip_reselect_rows: bool = False,
634
+ transacted: bool = True,
635
+ audit_behavior: AuditBehavior = None,
636
+ audit_user_comment: str = None,
510
637
  timeout: int = _default_timeout,
511
638
  ):
512
639
  return insert_rows(
513
- self.server_context, schema_name, query_name, rows, container_path, timeout
640
+ self.server_context,
641
+ schema_name,
642
+ query_name,
643
+ rows,
644
+ container_path,
645
+ skip_reselect_rows,
646
+ transacted,
647
+ audit_behavior,
648
+ audit_user_comment,
649
+ timeout
514
650
  )
515
651
 
516
652
  @functools.wraps(select_rows)
@@ -522,7 +658,7 @@ class QueryWrapper:
522
658
  filter_array: List[QueryFilter] = None,
523
659
  container_path: str = None,
524
660
  columns=None,
525
- max_rows: int = None,
661
+ max_rows: int = -1,
526
662
  sort: str = None,
527
663
  offset: int = None,
528
664
  container_filter: str = None,
@@ -566,8 +702,45 @@ class QueryWrapper:
566
702
  query_name: str,
567
703
  rows: List[any],
568
704
  container_path: str = None,
705
+ transacted: bool = True,
706
+ audit_behavior: AuditBehavior = None,
707
+ audit_user_comment: str = None,
569
708
  timeout: int = _default_timeout,
570
709
  ):
571
710
  return update_rows(
572
- self.server_context, schema_name, query_name, rows, container_path, timeout
711
+ self.server_context,
712
+ schema_name,
713
+ query_name,
714
+ rows,
715
+ container_path,
716
+ transacted,
717
+ audit_behavior,
718
+ audit_user_comment,
719
+ timeout
720
+ )
721
+
722
+ @functools.wraps(move_rows)
723
+ def move_rows(
724
+ self,
725
+ target_container_path: str,
726
+ schema_name: str,
727
+ query_name: str,
728
+ rows: any,
729
+ container_path: str = None,
730
+ transacted: bool = True,
731
+ audit_behavior: AuditBehavior = None,
732
+ audit_user_comment: str = None,
733
+ timeout: int = _default_timeout,
734
+ ):
735
+ return move_rows(
736
+ self.server_context,
737
+ target_container_path,
738
+ schema_name,
739
+ query_name,
740
+ rows,
741
+ container_path,
742
+ transacted,
743
+ audit_behavior,
744
+ audit_user_comment,
745
+ timeout
573
746
  )
labkey/utils.py CHANGED
@@ -16,6 +16,8 @@
16
16
  import json
17
17
  from functools import wraps
18
18
  from datetime import date, datetime
19
+ from base64 import b64encode
20
+ from urllib import parse
19
21
 
20
22
 
21
23
  # Issue #14: json.dumps on datetime throws TypeError
@@ -71,3 +73,21 @@ def transform_helper(user_transform_func, file_path_run_properties):
71
73
  row = [str(el).strip() for el in row]
72
74
  row = "\t".join(row)
73
75
  file_out.write(row + "\n")
76
+
77
+
78
+ def btoa(value: str) -> str:
79
+ if not value:
80
+ return value
81
+ binary = value.encode("utf-8")
82
+ return b64encode(binary).decode()
83
+
84
+
85
+ def encode_uri_component(value: str) -> str:
86
+ # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
87
+ return parse.quote(value, encoding="utf-8", safe="-_.!~*'()")
88
+
89
+
90
+ def waf_encode(value: str) -> str:
91
+ if value:
92
+ return "/*{{base64/x-www-form-urlencoded/wafText}}*/" + btoa(encode_uri_component(value))
93
+ return value
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: labkey
3
- Version: 2.6.0
3
+ Version: 3.0.0
4
4
  Summary: Python client API for LabKey Server
5
5
  Home-page: https://github.com/LabKey/labkey-api-python
6
6
  Author: LabKey
@@ -9,7 +9,6 @@ Maintainer: Alan Vezina
9
9
  Maintainer-email: alanv@labkey.com
10
10
  License: Apache License 2.0
11
11
  Keywords: labkey api client
12
- Platform: UNKNOWN
13
12
  Classifier: Development Status :: 4 - Beta
14
13
  Classifier: Environment :: Console
15
14
  Classifier: Intended Audience :: Science/Research
@@ -20,6 +19,7 @@ Classifier: Operating System :: Microsoft
20
19
  Classifier: Operating System :: POSIX
21
20
  Classifier: Programming Language :: Python :: 3
22
21
  Classifier: Topic :: Scientific/Engineering
22
+ License-File: LICENSE.txt
23
23
  Requires-Dist: requests
24
24
  Provides-Extra: test
25
25
  Requires-Dist: pytest ; extra == 'test'
@@ -28,5 +28,3 @@ Requires-Dist: mock ; extra == 'test'
28
28
  Requires-Dist: pytest-cov ; extra == 'test'
29
29
 
30
30
  Python client API for LabKey Server. Supports query and experiment APIs.
31
-
32
-
@@ -1,16 +1,16 @@
1
- labkey/__init__.py,sha256=tOjisNuXTI8emw2lhq5cv6P4e79bfS5tPyitf_9NoHY,695
1
+ labkey/__init__.py,sha256=q1xx8gL3h06R1DGXoOOInvVNbmuIOmuCexBPMyEApxM,695
2
2
  labkey/api_wrapper.py,sha256=ks6q5qwcGkutg2m5sMdTvryhfK42yltfPCV5iLPi22k,1351
3
3
  labkey/container.py,sha256=DXmLhGsNnN_QLXa_tMCM0Xf_Kkz7B8KjRFhJT5I4FtY,5497
4
4
  labkey/domain.py,sha256=SABG7BfSqQGJr8DPjUsvhi8C7xP2MTpkq24sdtAu4J8,22486
5
5
  labkey/exceptions.py,sha256=VtuKphEczSsfHAXgWRv-2HRzxSiObBnOEC_sgEPPR3c,2929
6
6
  labkey/experiment.py,sha256=Wtuz52bhuvDWk_o2AbTw7SJnwEji2iD6Q04ct0PWSxE,8804
7
- labkey/query.py,sha256=b4HJXCbwhFQbKnd1M9VbuvrDvfszpEBCH2I7Je4jE2U,18059
7
+ labkey/query.py,sha256=0Hp8P-mFuqurGlVbF71BN3Woz6tZfdweRKW0s4GFsh4,23995
8
8
  labkey/security.py,sha256=cVrlYbb7Yogjo9L1exGKgpscRFEljBpzFITQZWHW2X8,15284
9
9
  labkey/server_context.py,sha256=UGf4fJ9Cw_YIM_DwdPVP8WgKORt5aO_4bFCz14rjsrg,6950
10
10
  labkey/storage.py,sha256=WpgpTWQzgig_qJXMGszFcFjtf8oMd2-6TBehSkpJPUg,6144
11
- labkey/utils.py,sha256=rfZM1LT5iPOgVbKcOLUuWh59LqXYV-g3zoQUKwKcz-I,2651
12
- labkey-2.6.0.dist-info/LICENSE.txt,sha256=xllut76FgcGL5zbIRvuRc7aezPbvlMUTWJPsVr2Sugg,11358
13
- labkey-2.6.0.dist-info/METADATA,sha256=JLFyY0uy-EiA4s7V_6R87lYGjhDLaEuXBtEqAIHq5nY,1070
14
- labkey-2.6.0.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92
15
- labkey-2.6.0.dist-info/top_level.txt,sha256=DQIk1fQNg7NxxBsEt_K7k-aopiH87jmnU98zwDp0n04,7
16
- labkey-2.6.0.dist-info/RECORD,,
11
+ labkey/utils.py,sha256=oL6qmHkpzLTm_9c7gSEzumv_MVh5s8fj6bOrbuslrV0,3233
12
+ labkey-3.0.0.dist-info/LICENSE.txt,sha256=xllut76FgcGL5zbIRvuRc7aezPbvlMUTWJPsVr2Sugg,11358
13
+ labkey-3.0.0.dist-info/METADATA,sha256=BtwRKk5F9ja7CD37QvyCljOi0_R9Dq-10uUS0OH3BHQ,1076
14
+ labkey-3.0.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
15
+ labkey-3.0.0.dist-info/top_level.txt,sha256=DQIk1fQNg7NxxBsEt_K7k-aopiH87jmnU98zwDp0n04,7
16
+ labkey-3.0.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.36.2)
2
+ Generator: bdist_wheel (0.42.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5