benchling-sdk 1.21.0__tar.gz → 1.21.2__tar.gz

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.
Files changed (125) hide show
  1. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/PKG-INFO +1 -1
  2. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/config/framework.py +2 -2
  3. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/config/helpers.py +6 -5
  4. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/config/mock_config.py +4 -4
  5. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/helpers/webhook_helpers.py +26 -8
  6. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/status/framework.py +6 -6
  7. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/status/helpers.py +2 -0
  8. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/auth/client_credentials_oauth2.py +5 -4
  9. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/benchling.py +2 -2
  10. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/errors.py +4 -3
  11. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/helpers/retry_helpers.py +1 -1
  12. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/helpers/serialization_helpers.py +7 -4
  13. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/helpers/task_helpers.py +7 -4
  14. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/base_service.py +5 -4
  15. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/beta/v2_beta_data_frame_service.py +16 -8
  16. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/blob_service.py +6 -3
  17. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/organization_service.py +10 -5
  18. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/team_service.py +14 -7
  19. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/v2_alpha_service.py +2 -2
  20. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/v2_beta_service.py +2 -2
  21. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/v2_stable_service.py +3 -3
  22. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2_service.py +1 -1
  23. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/pyproject.toml +60 -22
  24. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/LICENSE +0 -0
  25. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/README.md +0 -0
  26. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/__init__.py +0 -0
  27. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/__init__.py +0 -0
  28. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/canvas/__init__.py +0 -0
  29. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/canvas/errors.py +0 -0
  30. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/canvas/framework.py +0 -0
  31. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/canvas/types.py +0 -0
  32. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/config/__init__.py +0 -0
  33. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/config/cryptography_helpers.py +0 -0
  34. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/config/decryption_provider.py +0 -0
  35. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/config/errors.py +0 -0
  36. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/config/types.py +0 -0
  37. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/framework.py +0 -0
  38. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/helpers/__init__.py +0 -0
  39. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/helpers/manifest_helpers.py +0 -0
  40. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/status/__init__.py +0 -0
  41. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/status/errors.py +0 -0
  42. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/status/types.py +0 -0
  43. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/apps/types.py +0 -0
  44. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/auth/__init__.py +0 -0
  45. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/auth/api_key_auth.py +0 -0
  46. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/auth/bearer_token_auth.py +0 -0
  47. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/docs/__init__.py +0 -0
  48. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/docs/__main__.py +0 -0
  49. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/helpers/__init__.py +0 -0
  50. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/helpers/client_helpers.py +0 -0
  51. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/helpers/constants.py +0 -0
  52. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/helpers/decorators.py +0 -0
  53. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/helpers/file_helpers.py +0 -0
  54. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/helpers/logging_helpers.py +0 -0
  55. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/helpers/package_helpers.py +0 -0
  56. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/helpers/pagination_helpers.py +0 -0
  57. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/helpers/response_helpers.py +0 -0
  58. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/helpers/transaction_manager.py +0 -0
  59. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/models/__init__.py +0 -0
  60. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/models/webhooks/__init__.py +0 -0
  61. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/models/webhooks/v0/__init__.py +0 -0
  62. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/py.typed +0 -0
  63. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/__init__.py +0 -0
  64. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/__init__.py +0 -0
  65. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/alpha/__init__.py +0 -0
  66. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/alpha/v2_alpha_app_service.py +0 -0
  67. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/alpha/v2_alpha_assembly_service.py +0 -0
  68. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/beta/__init__.py +0 -0
  69. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/beta/v2_beta_analysis_service.py +0 -0
  70. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/beta/v2_beta_app_definition_service.py +0 -0
  71. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/beta/v2_beta_app_service.py +0 -0
  72. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/beta/v2_beta_audit_service.py +0 -0
  73. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/beta/v2_beta_collaboration_service.py +0 -0
  74. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/beta/v2_beta_entry_service.py +0 -0
  75. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/beta/v2_beta_folder_service.py +0 -0
  76. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/beta/v2_beta_project_service.py +0 -0
  77. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/beta/v2_beta_worklist_service.py +0 -0
  78. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/__init__.py +0 -0
  79. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/aa_sequence_service.py +0 -0
  80. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/api_service.py +0 -0
  81. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/app_service.py +0 -0
  82. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/assay_result_service.py +0 -0
  83. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/assay_run_service.py +0 -0
  84. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/box_service.py +0 -0
  85. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/codon_usage_table_service.py +0 -0
  86. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/container_service.py +0 -0
  87. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/custom_entity_service.py +0 -0
  88. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/custom_notation_service.py +0 -0
  89. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/dna_alignments_service.py +0 -0
  90. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/dna_oligo_service.py +0 -0
  91. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/dna_sequence_service.py +0 -0
  92. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/dropdown_service.py +0 -0
  93. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/entity_service.py +0 -0
  94. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/entry_service.py +0 -0
  95. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/enzyme_service.py +0 -0
  96. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/event_service.py +0 -0
  97. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/export_service.py +0 -0
  98. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/feature_library_service.py +0 -0
  99. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/folder_service.py +0 -0
  100. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/instrument_query_service.py +0 -0
  101. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/inventory_service.py +0 -0
  102. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/lab_automation_service.py +0 -0
  103. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/label_template_service.py +0 -0
  104. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/location_service.py +0 -0
  105. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/mixture_service.py +0 -0
  106. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/molecule_service.py +0 -0
  107. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/monomer_service.py +0 -0
  108. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/nucleotide_alignments_service.py +0 -0
  109. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/oligo_service.py +0 -0
  110. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/plate_service.py +0 -0
  111. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/printer_service.py +0 -0
  112. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/project_service.py +0 -0
  113. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/registry_service.py +0 -0
  114. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/request_service.py +0 -0
  115. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/rna_oligo_service.py +0 -0
  116. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/rna_sequence_service.py +0 -0
  117. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/schema_service.py +0 -0
  118. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/task_service.py +0 -0
  119. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/user_service.py +0 -0
  120. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/warehouse_service.py +0 -0
  121. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/workflow_flowchart_config_version_service.py +0 -0
  122. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/workflow_flowchart_service.py +0 -0
  123. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/workflow_output_service.py +0 -0
  124. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/workflow_task_group_service.py +0 -0
  125. {benchling_sdk-1.21.0 → benchling_sdk-1.21.2}/benchling_sdk/services/v2/stable/workflow_task_service.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: benchling-sdk
3
- Version: 1.21.0
3
+ Version: 1.21.2
4
4
  Summary: SDK for interacting with the Benchling Platform.
5
5
  License: Apache-2.0
6
6
  Author: Benchling Support
@@ -228,7 +228,7 @@ class ConfigItemStore:
228
228
  _configuration_provider: ConfigProvider
229
229
  _configuration: Optional[List[ConfigurationReference]] = None
230
230
  _configuration_dict: Optional[Dict[ConfigItemPath, ConfigItemWrapper]] = None
231
- _array_path_row_names: Dict[Tuple[str, ...], OrderedSet[str]] = dict()
231
+ _array_path_row_names: Dict[Tuple[str, ...], OrderedSet[str]]
232
232
 
233
233
  def __init__(self, configuration_provider: ConfigProvider):
234
234
  """
@@ -302,7 +302,7 @@ class ConfigItemStore:
302
302
  # The +1 is the name of the array row
303
303
  if len(config_item.path) >= len(path) + 1
304
304
  # Ignoring flake8 error E203 because black keeps putting in whitespace padding :
305
- and config_item.path[0 : len(path_tuple)] == path # noqa: E203
305
+ and config_item.path[0 : len(path_tuple)] == path
306
306
  and config_item.value is not None
307
307
  ]
308
308
  )
@@ -1,6 +1,6 @@
1
1
  from datetime import datetime
2
2
  from enum import Enum
3
- from functools import lru_cache
3
+ from functools import cache
4
4
  from typing import cast, List, Optional, Union
5
5
 
6
6
  from benchling_api_client.v2.beta.extensions import Enums
@@ -47,7 +47,8 @@ class _UnsupportedSubTypeError(Exception):
47
47
 
48
48
 
49
49
  class _ScalarConfigTypes(Enums.KnownString):
50
- """Enum type copied from an earlier version of benchling-api-client, for internal use only.
50
+ """
51
+ Enum type copied from an earlier version of benchling-api-client, for internal use only.
51
52
 
52
53
  See BNCH-108704.
53
54
  """
@@ -65,12 +66,12 @@ class _ScalarConfigTypes(Enums.KnownString):
65
66
  return str(self.value)
66
67
 
67
68
  @staticmethod
68
- @lru_cache(maxsize=None)
69
+ @cache
69
70
  def of_unknown(val: str) -> "_ScalarConfigTypes":
70
71
  if not isinstance(val, str):
71
72
  raise ValueError(f"Value of _ScalarConfigTypes must be a string (encountered: {val})")
72
73
  newcls = Enum("_ScalarConfigTypes", {"_UNKNOWN": val}, type=Enums.UnknownString) # type: ignore
73
- return cast(_ScalarConfigTypes, getattr(newcls, "_UNKNOWN"))
74
+ return cast(_ScalarConfigTypes, newcls._UNKNOWN)
74
75
 
75
76
 
76
77
  def _field_definitions_from_dependency(
@@ -122,7 +123,7 @@ def _enum_from_dependency(
122
123
 
123
124
 
124
125
  # TODO BNCH-57036 All element definitions currently deserialize to UnknownType. Hack around this temporarily
125
- def _fix_element_definition_deserialization(
126
+ def _fix_element_definition_deserialization( # noqa:PLR0911
126
127
  element: Union[UnknownType, _ArrayElementDependency]
127
128
  ) -> _ArrayElementDependency:
128
129
  if isinstance(element, UnknownType):
@@ -345,7 +345,7 @@ def mock_text_app_config_item(path: List[str], value: Optional[str]) -> TextAppC
345
345
  )
346
346
 
347
347
 
348
- def _mock_dependency(
348
+ def _mock_dependency( # noqa:PLR0911
349
349
  dependency: ManifestDependencies,
350
350
  parent_path: Optional[List[str]] = None,
351
351
  ) -> List[AppConfigItem]:
@@ -451,7 +451,7 @@ def _convert_entity_subtype(manifest_subtype: SchemaDependencySubtypesBeta) -> S
451
451
  return SchemaDependencySubtypes(source_value)
452
452
 
453
453
 
454
- def _mock_scalar_dependency(
454
+ def _mock_scalar_dependency( # noqa:PLR0911
455
455
  dependency: ManifestScalarConfig, parent_path: Optional[List[str]] = None
456
456
  ) -> AppConfigItem:
457
457
  parent_path = parent_path if parent_path else []
@@ -502,7 +502,7 @@ def _mock_array_dependency(
502
502
  ) -> List[AppConfigItem]:
503
503
  config_rows = []
504
504
  parent_path = parent_path if parent_path else []
505
- for i in range(rows):
505
+ for _ in range(rows):
506
506
  row = _mock_array_row(dependency, parent_path=parent_path)
507
507
  elements = _element_definition_from_dependency(dependency)
508
508
  element_configs = [_mock_dependency(element, row.path) for element in elements]
@@ -594,7 +594,7 @@ def _mock_linked_resource(id: str, name: Optional[str] = None) -> LinkedAppConfi
594
594
  return LinkedAppConfigResourceSummary(id=id, name=name if name else _random_string("Resource Name"))
595
595
 
596
596
 
597
- def _mock_scalar_value(
597
+ def _mock_scalar_value( # noqa:PLR0911
598
598
  dependency: ManifestScalarConfig,
599
599
  ) -> Union[bool, date, datetime, int, float, str, Dict[str, Union[str, float]]]:
600
600
  """Mock a scalar config value from its manifest definition."""
@@ -1,6 +1,6 @@
1
1
  import base64
2
2
  from datetime import datetime, timedelta, timezone
3
- from typing import Any, cast, List, Mapping, Optional, Protocol, Union
3
+ from typing import cast, List, Optional, Protocol, Union
4
4
 
5
5
  from benchling_api_client.v2.benchling_client import BenchlingApiClient
6
6
  import httpx
@@ -12,6 +12,21 @@ from benchling_sdk.helpers.package_helpers import _required_packages_context, Ex
12
12
  from benchling_sdk.services.v2.stable.api_service import build_json_response
13
13
 
14
14
 
15
+ class HeadersMapping(Protocol):
16
+ """
17
+ A general type for objects that represent request headers.
18
+
19
+ This can be a dict, or any `Mapping[str, str]`, or an instance of a class like
20
+ Flask's Headers class which is dict-like to a limited degree.
21
+ """
22
+
23
+ def __contains__(self, key: str) -> bool:
24
+ pass
25
+
26
+ def __getitem__(self, key: str) -> str:
27
+ pass
28
+
29
+
15
30
  class WebhookVerificationError(Exception):
16
31
  """
17
32
  Webhook Verification Error.
@@ -146,7 +161,7 @@ def jwks_by_app_definition(
146
161
 
147
162
 
148
163
  def verify_app_installation(
149
- app_id: str, data: str, headers: Mapping[str, Any], jwk_function: Optional[LegacyGetJwksFunction] = None
164
+ app_id: str, data: str, headers: HeadersMapping, jwk_function: Optional[LegacyGetJwksFunction] = None
150
165
  ) -> None:
151
166
  """
152
167
  Verify a webhook for an app installation (Deprecated).
@@ -165,7 +180,7 @@ def verify_app_installation(
165
180
  def verify(
166
181
  app_definition_id: str,
167
182
  data: str,
168
- headers: Mapping[str, Any],
183
+ headers: HeadersMapping,
169
184
  jwk_function: Optional[GetJwksFunction] = None,
170
185
  ) -> None:
171
186
  """
@@ -174,6 +189,9 @@ def verify(
174
189
  Verifies that a webhook was a valid webhook from Benchling.
175
190
  Raises WebhookVerificationError if the webhook could not be verified.
176
191
  Resolves JWKs from Benchling with default settings. Pass jwk_function for customization.
192
+
193
+ The headers parameter can be a dict, or a dict-like object such as the Headers type
194
+ from Flask.
177
195
  """
178
196
  default_jwk_function: GetJwksFunction = jwks_by_app_definition
179
197
  _jwk_function: GetJwksFunction = default_jwk_function if jwk_function is None else jwk_function
@@ -201,7 +219,7 @@ def _has_valid_signature(to_verify: str, jwks: jwk.JWKSet, encoded_signatures: L
201
219
  def _verify(
202
220
  app_installation_or_definition_id: str,
203
221
  data: str,
204
- headers: Mapping[str, Any],
222
+ headers: HeadersMapping,
205
223
  jwk_function: Union[GetJwksFunction, LegacyGetJwksFunction],
206
224
  ) -> None:
207
225
  _verify_headers_present(headers)
@@ -215,7 +233,7 @@ def _verify(
215
233
  raise WebhookVerificationError("No matching signature found")
216
234
 
217
235
 
218
- def _der_signatures_from_versioned_signatures(versioned_signatures: str) -> List[str]:
236
+ def _der_signatures_from_versioned_signatures(versioned_signatures: List[str]) -> List[str]:
219
237
  """
220
238
  Parse and return a list of ders signatures from a single string.
221
239
 
@@ -231,7 +249,7 @@ def _der_signatures_from_versioned_signatures(versioned_signatures: str) -> List
231
249
  return der_signatures
232
250
 
233
251
 
234
- def _verify_headers_present(headers: Mapping[str, Any]) -> None:
252
+ def _verify_headers_present(headers: HeadersMapping) -> None:
235
253
  """
236
254
  Verify Headers Present.
237
255
 
@@ -258,8 +276,8 @@ def _verify_timestamp(timestamp_header: str) -> None:
258
276
  now = datetime.now(tz=timezone.utc)
259
277
  try:
260
278
  timestamp = datetime.fromtimestamp(float(timestamp_header), tz=timezone.utc)
261
- except Exception:
262
- raise WebhookVerificationError("Invalid Signature Headers")
279
+ except Exception as exc:
280
+ raise WebhookVerificationError("Invalid Signature Headers") from exc
263
281
  if timestamp < (now - webhook_tolerance):
264
282
  raise WebhookVerificationError("Message timestamp too old")
265
283
  if timestamp > (now + webhook_tolerance):
@@ -5,7 +5,7 @@ from contextlib import AbstractContextManager
5
5
  from types import TracebackType
6
6
  from typing import cast, Iterable, List, Optional, Protocol, Type, TYPE_CHECKING, Union
7
7
 
8
- from benchling_api_client.v2.stable.types import Unset, UNSET
8
+ from benchling_api_client.v2.stable.types import UNSET, Unset
9
9
 
10
10
  from benchling_sdk.apps.status.errors import (
11
11
  AppUserFacingError,
@@ -286,10 +286,7 @@ class SessionClosingContextExitHandler(SessionContextExitHandler):
286
286
  error_messages: Optional[Iterable[AppSessionMessageCreate]] = [
287
287
  AppSessionMessageCreate(_DEFAULT_APP_ERROR_MESSAGE, style=AppSessionMessageStyle.ERROR)
288
288
  ],
289
- error_processors: List[Type[SessionContextErrorProcessor]] = [
290
- AppUserFacingErrorProcessor,
291
- BenchlingBadRequestErrorProcessor,
292
- ],
289
+ error_processors: Optional[List[Type[SessionContextErrorProcessor]]] = None,
293
290
  enable_attached_canvas_on_error: bool = True,
294
291
  ):
295
292
  """
@@ -300,7 +297,10 @@ class SessionClosingContextExitHandler(SessionContextExitHandler):
300
297
  """
301
298
  self._success_messages = success_messages
302
299
  self._error_messages = error_messages
303
- self._error_processors = error_processors
300
+ self._error_processors = error_processors or [
301
+ AppUserFacingErrorProcessor,
302
+ BenchlingBadRequestErrorProcessor,
303
+ ]
304
304
  self._enable_attached_canvas_on_error = enable_attached_canvas_on_error
305
305
 
306
306
  def on_success(self, context: SessionContextManager) -> bool:
@@ -13,6 +13,7 @@ def ref(reference: ReferencedSessionLinkType) -> str:
13
13
  Example:
14
14
  dna_sequence = benchling.dna_sequences.get_by_id("seq_1234")
15
15
  AppSessionMessageCreate(f"This is my DNA sequence {ref(dna_sequence)} for analysis")
16
+
16
17
  """
17
18
  return ref_by_id(reference.id)
18
19
 
@@ -28,6 +29,7 @@ def ref_by_id(reference_id: str) -> str:
28
29
  Example:
29
30
  dna_sequence_id: str = "seq_asQya4lk"
30
31
  AppSessionMessageCreate(f"This is my DNA sequence {ref_by_id(dna_sequence_id)} for analysis")
32
+
31
33
  """
32
34
  assert reference_id, "reference_id cannot be empty or None"
33
35
  return _encode_id(reference_id)
@@ -1,9 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import base64
4
- from datetime import datetime, timedelta
4
+ from datetime import datetime, timedelta, timezone
5
5
  from json import JSONDecodeError
6
6
  import threading
7
+ import typing
7
8
  from typing import NoReturn, Optional
8
9
  from urllib.parse import urljoin
9
10
 
@@ -31,7 +32,7 @@ class Token:
31
32
 
32
33
  def valid(self) -> bool:
33
34
  """Return whether token is still valid for use or should be regenerated."""
34
- return datetime.now() < self.refresh_time
35
+ return datetime.now(timezone.utc) < self.refresh_time
35
36
 
36
37
  @classmethod
37
38
  def from_token_response(cls, token_response) -> Token:
@@ -50,7 +51,7 @@ class Token:
50
51
  # Add in a buffer to safeguard against race conditions with token expiration.
51
52
  # Buffer is 10% of expires_in time, clamped between [1, MINIMUM_TOKEN_EXPIRY_BUFFER] seconds.
52
53
  refresh_delta = expires_in - max(1, min(MINIMUM_TOKEN_EXPIRY_BUFFER, expires_in * 0.1))
53
- refresh_time = datetime.now() + timedelta(seconds=refresh_delta)
54
+ refresh_time = datetime.now(timezone.utc) + timedelta(seconds=refresh_delta)
54
55
  return cls(access_token, refresh_time)
55
56
 
56
57
 
@@ -62,7 +63,7 @@ class ClientCredentialsOAuth2(AuthorizationMethod):
62
63
  type.
63
64
  """
64
65
 
65
- _data_for_token_request = {
66
+ _data_for_token_request: typing.ClassVar[dict] = {
66
67
  "grant_type": "client_credentials",
67
68
  }
68
69
 
@@ -96,7 +96,7 @@ _DEFAULT_BASE_PATH = "/api/v2"
96
96
  _DEFAULT_RETRY_STRATEGY = RetryStrategy()
97
97
 
98
98
 
99
- class Benchling(object):
99
+ class Benchling:
100
100
  """
101
101
  A facade for interactions with the Benchling platform.
102
102
 
@@ -213,7 +213,7 @@ class Benchling(object):
213
213
 
214
214
  See https://benchling.com/api/reference#/Apps
215
215
  and https://docs.benchling.com/docs/getting-started-benchling-apps
216
- """
216
+ """ # noqa:RUF002 # Ruff gets confused by a trailing apostrophe with a plural noun
217
217
  return self.v2.stable.apps
218
218
 
219
219
  @property
@@ -26,7 +26,8 @@ logger = default_logger()
26
26
 
27
27
  @dataclass
28
28
  class BenchlingError(Exception):
29
- """An error resulting from communicating with the Benchling API.
29
+ """
30
+ An error resulting from communicating with the Benchling API.
30
31
 
31
32
  This could be an error returned from the API intentionally (e.g., 400 Bad Request) or an
32
33
  unexpected transport error (e.g., 502 Bad Gateway)
@@ -53,7 +54,7 @@ class BenchlingError(Exception):
53
54
  ]
54
55
 
55
56
  @classmethod
56
- def from_response(cls, response: Response) -> "BenchlingError":
57
+ def from_response(cls, response: Response) -> BenchlingError:
57
58
  """Create a BenchlingError from a generated Response."""
58
59
  json_body = _parse_error_body(response.content)
59
60
  return cls(
@@ -95,7 +96,7 @@ class RegistrationError(Exception):
95
96
  task_status: Optional[AsyncTaskStatus] = None
96
97
 
97
98
  @classmethod
98
- def from_task(cls, task: AsyncTask) -> "RegistrationError":
99
+ def from_task(cls, task: AsyncTask) -> RegistrationError:
99
100
  """Create a RegistrationError from a failed AsyncTask."""
100
101
  task_errors = unset_as_none(task.errors)
101
102
  errors_dict: Dict[Any, Any] = task_errors.to_dict() if task_errors else dict() # type: ignore
@@ -14,7 +14,7 @@ logging.getLogger("backoff").setLevel(logging.CRITICAL)
14
14
 
15
15
 
16
16
  @dataclass(frozen=True, eq=True)
17
- class RetryStrategy(object):
17
+ class RetryStrategy:
18
18
  """Specify a strategy for automatically retrying failed HTTP calls."""
19
19
 
20
20
  # Passing in None results in unbounded retries
@@ -1,7 +1,7 @@
1
1
  from dataclasses import dataclass
2
2
  from typing import Any, Dict, Iterable, Optional, Type, TypeVar, Union
3
3
 
4
- from benchling_api_client.v2.types import Unset, UNSET
4
+ from benchling_api_client.v2.types import UNSET, Unset
5
5
  from dataclasses_json import DataClassJsonMixin
6
6
 
7
7
  from benchling_sdk.models import CustomFields, Field, Fields, SchemaFieldsQueryParam
@@ -29,7 +29,8 @@ class SerializableModel(DataClassJsonMixin):
29
29
 
30
30
  @dataclass
31
31
  class DeserializableModel(DataClassJsonMixin):
32
- """Provide an interface for deserialization to a custom model.
32
+ """
33
+ Provide an interface for deserialization to a custom model.
33
34
 
34
35
  For deserializing models when using raw API calls (e.g., Benchling.api)
35
36
  Override deserialize() for customized behavior.
@@ -50,7 +51,8 @@ class DeserializableModelNoContent(DeserializableModel):
50
51
 
51
52
 
52
53
  def optional_array_query_param(inputs: Optional[Iterable[str]]) -> Optional[str]:
53
- """Collapse an Iterable to a comma-separated string if present.
54
+ """
55
+ Collapse an Iterable to a comma-separated string if present.
54
56
 
55
57
  Add leading and trailing quotes if the item contains "," and not quoted
56
58
  """
@@ -58,7 +60,8 @@ def optional_array_query_param(inputs: Optional[Iterable[str]]) -> Optional[str]
58
60
 
59
61
 
60
62
  def array_query_param(inputs: Iterable[str]) -> str:
61
- """Collapse an Iterable to a comma-separated string.
63
+ """
64
+ Collapse an Iterable to a comma-separated string.
62
65
 
63
66
  Add leading and trailing quotes if the item contains "," and not quoted
64
67
  """
@@ -37,7 +37,8 @@ EMPTY_TASK_RESPONSE = EmptyTaskResponse()
37
37
 
38
38
 
39
39
  class TaskHelper(AsyncTaskLink, Generic[ResponseT]):
40
- """Used by Benchling async task endpoints to provide the task response in an appropriate type.
40
+ """
41
+ Used by Benchling async task endpoints to provide the task response in an appropriate type.
41
42
 
42
43
  In the API spec, endpoints that create a long-running task are defined as returning an
43
44
  :py:class:`benchling_sdk.models.AsyncTaskLink`, which can be used with
@@ -70,12 +71,13 @@ class TaskHelper(AsyncTaskLink, Generic[ResponseT]):
70
71
 
71
72
  if response_class is not EmptyTaskResponse:
72
73
  assert hasattr(response_class, "from_dict")
73
- self._response_decoder = getattr(response_class, "from_dict")
74
+ self._response_decoder = getattr(response_class, "from_dict") # noqa: B009
74
75
 
75
76
  def wait_for_completion(
76
77
  self, interval_wait_seconds: int = 1, max_wait_seconds: int = 600
77
78
  ) -> TaskCompletion[ResponseT]:
78
- """Wait for the task to succeed or fail.
79
+ """
80
+ Wait for the task to succeed or fail.
79
81
 
80
82
  This is equivalent to the :py:meth:`benchling_sdk.services.v2.stable.task_service.TaskService.wait_for_task`
81
83
  method in :py:class:`benchling_sdk.services.v2.stable.task_service.TaskService`, except that
@@ -116,7 +118,8 @@ class TaskHelper(AsyncTaskLink, Generic[ResponseT]):
116
118
  )
117
119
 
118
120
  def wait_for_response(self, interval_wait_seconds: int = 1, max_wait_seconds: int = 600) -> ResponseT:
119
- """Wait for the task and return the response object on success, or raise an exception on failure.
121
+ """
122
+ Wait for the task and return the response object on success, or raise an exception on failure.
120
123
 
121
124
  This is a convenience method for calling :py:meth:`wait_for_completion` and then getting the
122
125
  `response` property of the returned object if the task succeeded, in cases where you're not
@@ -1,5 +1,5 @@
1
1
  from abc import ABC
2
- from typing import Type, TYPE_CHECKING
2
+ from typing import Optional, Type, TYPE_CHECKING
3
3
 
4
4
  from benchling_api_client.v2.stable.client import Client
5
5
  from benchling_api_client.v2.types import Response
@@ -17,7 +17,7 @@ class BaseService(ABC):
17
17
  _client: Client
18
18
  _retry_strategy: RetryStrategy
19
19
 
20
- def __init__(self, client: Client, retry_strategy: RetryStrategy = RetryStrategy()):
20
+ def __init__(self, client: Client, retry_strategy: Optional[RetryStrategy] = None):
21
21
  """
22
22
  Initialize a service.
23
23
 
@@ -25,7 +25,7 @@ class BaseService(ABC):
25
25
  :param retry_strategy: Retry strategy for failed HTTP calls
26
26
  """
27
27
  self._client = client
28
- self._retry_strategy = retry_strategy
28
+ self._retry_strategy = retry_strategy or RetryStrategy()
29
29
 
30
30
  @property
31
31
  def client(self) -> Client:
@@ -38,7 +38,8 @@ class BaseService(ABC):
38
38
  return self._retry_strategy
39
39
 
40
40
  def _create_service(self, cls):
41
- """Instantiate a service that derives from BaseService, with the same properties as this service.
41
+ """
42
+ Instantiate a service that derives from BaseService, with the same properties as this service.
42
43
 
43
44
  Override this in alpha and beta services that use a client other than self._client.
44
45
  """
@@ -72,7 +72,8 @@ class V2BetaDataFrameService(BaseService):
72
72
  input_bytes: Union[BytesIO, bytes],
73
73
  timeout_seconds: float = _DEFAULT_HTTP_TIMEOUT_UPLOAD_DATA_FRAME,
74
74
  ) -> None:
75
- """Upload bytes to an existing data frame.
75
+ """
76
+ Upload bytes to an existing data frame.
76
77
 
77
78
  :param url: The url provided by Benchling for uploading to the data frame
78
79
  :param input_bytes: Data to upload as bytes or BytesIO
@@ -90,7 +91,8 @@ class V2BetaDataFrameService(BaseService):
90
91
  def upload_file(
91
92
  self, url: str, file: Path, timeout_seconds: float = _DEFAULT_HTTP_TIMEOUT_UPLOAD_DATA_FRAME
92
93
  ) -> None:
93
- """Upload a file to an existing data frame.
94
+ """
95
+ Upload a file to an existing data frame.
94
96
 
95
97
  :param url: The url provided by Benchling for uploading to the data frame
96
98
  :param file: A valid Path to an existing file containing the data to upload
@@ -115,7 +117,8 @@ class V2BetaDataFrameService(BaseService):
115
117
  input_bytes: Union[BytesIO, bytes],
116
118
  timeout_seconds: float = _DEFAULT_HTTP_TIMEOUT_UPLOAD_DATA_FRAME,
117
119
  ) -> TaskHelper[DataFrame]:
118
- """Create a data frame from bytes or BytesIO data.
120
+ """
121
+ Create a data frame from bytes or BytesIO data.
119
122
 
120
123
  :param data_frame: The DataFrameCreate specification for the data. This must be provided, as it cannot be inferred from file names.
121
124
  :param input_bytes: Data to upload as bytes or BytesIO
@@ -151,7 +154,8 @@ class V2BetaDataFrameService(BaseService):
151
154
  data_frame: Optional[DataFrameCreate] = None,
152
155
  timeout_seconds: float = _DEFAULT_HTTP_TIMEOUT_UPLOAD_DATA_FRAME,
153
156
  ) -> TaskHelper[DataFrame]:
154
- """Create a data frame from file data.
157
+ """
158
+ Create a data frame from file data.
155
159
 
156
160
  :param file: A valid Path to an existing file containing the data to upload
157
161
  :param data_frame: The DataFrameCreate specification for the data. If not provided, it will be inferred from the file name
@@ -178,7 +182,8 @@ class V2BetaDataFrameService(BaseService):
178
182
  def download_data_frame_bytes(
179
183
  self, data_frame: DataFrame, timeout_seconds: float = _DEFAULT_HTTP_TIMEOUT_UPLOAD_DATA_FRAME
180
184
  ) -> List[BytesIO]:
181
- """Download data frame data to bytes.
185
+ """
186
+ Download data frame data to bytes.
182
187
 
183
188
  :param data_frame: The data frame to download
184
189
  :param timeout_seconds: Extends the normal HTTP timeout settings since DataFrame uploads can be large
@@ -211,7 +216,8 @@ class V2BetaDataFrameService(BaseService):
211
216
  destination_path: Optional[Path] = None,
212
217
  timeout_seconds: float = _DEFAULT_HTTP_TIMEOUT_UPLOAD_DATA_FRAME,
213
218
  ) -> List[Path]:
214
- """Download data frame data to files.
219
+ """
220
+ Download data frame data to files.
215
221
 
216
222
  :param data_frame: The data frame to download
217
223
  :param destination_path: A target directory to place the files. File names will be created based on the manifest item file names.
@@ -252,7 +258,8 @@ class V2BetaDataFrameService(BaseService):
252
258
  def download_data_frame_bytes_by_id(
253
259
  self, data_frame_id: str, timeout_seconds: float = _DEFAULT_HTTP_TIMEOUT_UPLOAD_DATA_FRAME
254
260
  ) -> List[BytesIO]:
255
- """Download data frame data to files by data_frame_id.
261
+ """
262
+ Download data frame data to files by data_frame_id.
256
263
 
257
264
  Fetches the data frame first, then downloads the files.
258
265
 
@@ -272,7 +279,8 @@ class V2BetaDataFrameService(BaseService):
272
279
  destination_path: Optional[Path] = None,
273
280
  timeout_seconds: float = _DEFAULT_HTTP_TIMEOUT_UPLOAD_DATA_FRAME,
274
281
  ) -> List[Path]:
275
- """Download data frame data to files by data_frame_id.
282
+ """
283
+ Download data frame data to files by data_frame_id.
276
284
 
277
285
  Fetches the data frame first, then downloads the files.
278
286
 
@@ -46,7 +46,8 @@ DEFAULT_CHUNK_SIZE_BYTES: int = MINIMUM_CHUNK_SIZE_BYTES
46
46
 
47
47
 
48
48
  def _write_blob_file(file_contents: BytesIO, file_path: Optional[Path] = None) -> Path:
49
- """Write bytes to a file. Will create a temp file if file_path isn't specified.
49
+ """
50
+ Write bytes to a file. Will create a temp file if file_path isn't specified.
50
51
 
51
52
  Returns the Path of the file written to, whether created or used.
52
53
  """
@@ -114,7 +115,8 @@ class BlobService(BaseService):
114
115
  timeout_seconds: float = DEFAULT_HTTP_TIMEOUT,
115
116
  chunk_size_bytes: int = DEFAULT_CHUNK_SIZE_BYTES,
116
117
  ) -> Blob:
117
- """Create a Benchling Blob from bytes or a BytesIO stream.
118
+ """
119
+ Create a Benchling Blob from bytes or a BytesIO stream.
118
120
 
119
121
  Will automatically attempt a multi-part upload if the stream appears larger
120
122
  than the API's maximum size for single Blobs.
@@ -172,7 +174,8 @@ class BlobService(BaseService):
172
174
  timeout_seconds: float = DEFAULT_HTTP_TIMEOUT,
173
175
  chunk_size_bytes: int = DEFAULT_CHUNK_SIZE_BYTES,
174
176
  ) -> Blob:
175
- """Create a Benchling Blob from a file.
177
+ """
178
+ Create a Benchling Blob from a file.
176
179
 
177
180
  Will automatically attempt a multi-part upload if the file appears larger
178
181
  than the API's maximum size for single Blobs.
@@ -157,7 +157,8 @@ class OrganizationService(BaseService):
157
157
  role: Optional[str] = None,
158
158
  page_size: Optional[int] = None,
159
159
  ) -> PageIterator[MembershipsPaginatedList]:
160
- """Return all organization memberships in the given organization.
160
+ """
161
+ Return all organization memberships in the given organization.
161
162
 
162
163
  See https://benchling.com/api/reference#/Organizations/listOrganizationMemberships
163
164
  """
@@ -169,7 +170,8 @@ class OrganizationService(BaseService):
169
170
 
170
171
  @api_method
171
172
  def get_membership(self, organization_id: str, user_id: str) -> Membership:
172
- """Get organization membership.
173
+ """
174
+ Get organization membership.
173
175
 
174
176
  See https://benchling.com/api/reference#/Organizations/getOrganizationMembership
175
177
  """
@@ -180,7 +182,8 @@ class OrganizationService(BaseService):
180
182
 
181
183
  @api_method
182
184
  def create_membership(self, organization_id: str, membership: MembershipCreate) -> Membership:
183
- """Create organization membership.
185
+ """
186
+ Create organization membership.
184
187
 
185
188
  See https://benchling.com/api/reference#/Organizations/createOrganizationMembership
186
189
  """
@@ -195,7 +198,8 @@ class OrganizationService(BaseService):
195
198
  def update_membership(
196
199
  self, organization_id: str, user_id: str, membership: MembershipUpdate
197
200
  ) -> Membership:
198
- """Update organization membership by user ID and organization ID.
201
+ """
202
+ Update organization membership by user ID and organization ID.
199
203
 
200
204
  See https://benchling.com/api/reference#/Organizations/updateOrganizationMembership
201
205
  """
@@ -209,7 +213,8 @@ class OrganizationService(BaseService):
209
213
 
210
214
  @api_method
211
215
  def delete_membership(self, organization_id: str, user_id: str) -> None:
212
- """Delete a single team membership.
216
+ """
217
+ Delete a single team membership.
213
218
 
214
219
  See https://benchling.com/api/reference#/Organizations/deleteOrganizationMembership
215
220
  """