reasoner-validator 3.9.2__tar.gz → 3.9.4__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 (41) hide show
  1. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/PKG-INFO +13 -3
  2. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/README.md +6 -0
  3. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/docs/validation_codes_dictionary.md +8 -8
  4. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/pyproject.toml +14 -4
  5. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/reasoner_validator/biolink/__init__.py +3 -1
  6. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/reasoner_validator/codes.yaml +7 -6
  7. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/reasoner_validator/validator.py +26 -3
  8. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/tests/test_biolink_compliance_validation.py +1 -1
  9. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/tests/test_response_validator.py +2 -3
  10. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/tests/test_workflows.py +29 -0
  11. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/LICENSE +0 -0
  12. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/docs/.nojekyll +0 -0
  13. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/docs/Makefile +0 -0
  14. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/docs/conf.py +0 -0
  15. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/docs/index.rst +0 -0
  16. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/docs/make.bat +0 -0
  17. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/docs/reasoner_validator.biolink.rst +0 -0
  18. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/docs/reasoner_validator.report.rst +0 -0
  19. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/docs/reasoner_validator.rst +0 -0
  20. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/docs/reasoner_validator.trapi.mapping.rst +0 -0
  21. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/docs/reasoner_validator.trapi.rst +0 -0
  22. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/docs/reasoner_validator.validation_codes.rst +0 -0
  23. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/docs/reasoner_validator.versioning.rst +0 -0
  24. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/reasoner_validator/__init__.py +0 -0
  25. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/reasoner_validator/github.py +0 -0
  26. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/reasoner_validator/message.py +0 -0
  27. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/reasoner_validator/report.py +0 -0
  28. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/reasoner_validator/sri/__init__.py +0 -0
  29. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/reasoner_validator/sri/util.py +0 -0
  30. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/reasoner_validator/trapi/__init__.py +19 -19
  31. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/reasoner_validator/trapi/mapping.py +0 -0
  32. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/reasoner_validator/validation_codes.py +0 -0
  33. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/reasoner_validator/versioning.py +0 -0
  34. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/reasoner_validator/versions.yaml +0 -0
  35. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/tests/__init__.py +0 -0
  36. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/tests/conftest.py +0 -0
  37. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/tests/test_data/patched_trapi_schema_v1.4.0-beta5.yaml +0 -0
  38. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/tests/test_semver.py +0 -0
  39. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/tests/test_trapi_versioning.py +0 -0
  40. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/tests/test_validate.py +0 -0
  41. {reasoner_validator-3.9.2 → reasoner_validator-3.9.4}/tests/test_validation_report.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: reasoner-validator
3
- Version: 3.9.2
3
+ Version: 3.9.4
4
4
  Summary: Validation tools for Reasoner API
5
5
  Home-page: https://github.com/NCATSTranslator
6
6
  License: MIT
@@ -23,10 +23,14 @@ Provides-Extra: web
23
23
  Requires-Dist: PyYAML (>=6.0,<7.0)
24
24
  Requires-Dist: bmt (>=1.1.2,<2.0.0)
25
25
  Requires-Dist: dictdiffer (>=0.9.0,<0.10.0)
26
- Requires-Dist: fastapi (>=0.68,<0.69) ; extra == "web"
26
+ Requires-Dist: fastapi (>=0.85.0,<0.86.0) ; extra == "web"
27
+ Requires-Dist: httpx (>=0.18.2,<0.19.0) ; extra == "web"
27
28
  Requires-Dist: jsonschema (>=4.17.3,<4.18.0)
28
29
  Requires-Dist: myst-parser (>=2.0.0,<3.0.0) ; extra == "docs"
29
30
  Requires-Dist: numpydoc (>=1.5.0,<2.0.0) ; extra == "docs"
31
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http ; extra == "web"
32
+ Requires-Dist: opentelemetry-instrumentation-fastapi ; extra == "web"
33
+ Requires-Dist: opentelemetry-instrumentation-httpx ; extra == "web"
30
34
  Requires-Dist: pydantic (>=1.10.11,<2.0.0)
31
35
  Requires-Dist: pytest (>=7.2.2,<8.0.0)
32
36
  Requires-Dist: pytest-cov (>=4.0.0,<5.0.0)
@@ -34,7 +38,7 @@ Requires-Dist: requests (>=2.28.1,<3.0.0)
34
38
  Requires-Dist: sphinx (>=6.2.1,<7.0.0) ; extra == "docs"
35
39
  Requires-Dist: sphinx-rtd-theme (>=1.2.2,<2.0.0) ; extra == "docs"
36
40
  Requires-Dist: urllib3 (>=1.26.15,<2.0.0)
37
- Requires-Dist: uvicorn (>=0.15,<0.16) ; extra == "web"
41
+ Requires-Dist: uvicorn ; extra == "web"
38
42
  Project-URL: Bug Tracker, https://github.com/NCATSTranslator/reasoner-validator/issues
39
43
  Project-URL: Change Log, https://github.com/NCATSTranslator/reasoner-validator/blob/master/CHANGELOG.md
40
44
  Project-URL: Documentation, https://translator-reasoner-validator.readthedocs.io/en/latest/
@@ -309,6 +313,12 @@ To minimize redundancy in validation messages, messages are uniquely indexed in
309
313
  1. the (codes.yaml recorded) dot-delimited validation code path string
310
314
  2. for messages with templated parameters, by a mandatory 'identifier' field (which is expected to exist as a field in a template if such template has one or more parameterized fields)
311
315
 
316
+ ### OpenTelemetry and Jaeger
317
+
318
+ The web service may be monitored for OpenTelemetry by setting an environment variable **TELEMETRY_ENDPOINT** to a suitable trace collecting endpoint in an application like [Jaeger](https://www.jaegertracing.io/) (see also the [Translator SRI Jaeger-Demo](https://github.com/TranslatorSRI/Jaeger-demo)).
319
+
320
+ **Note:** the current system Docker (Compose) design only supports OpenTemplate tracing using the internal Jaeger container and may require further refinements to enable use of an external telemetry collector.
321
+
312
322
  ### Running the Web Service within Docker
313
323
 
314
324
  The Reasoner Validator web service may be run inside a docker container, using Docker Compose.
@@ -266,6 +266,12 @@ To minimize redundancy in validation messages, messages are uniquely indexed in
266
266
  1. the (codes.yaml recorded) dot-delimited validation code path string
267
267
  2. for messages with templated parameters, by a mandatory 'identifier' field (which is expected to exist as a field in a template if such template has one or more parameterized fields)
268
268
 
269
+ ### OpenTelemetry and Jaeger
270
+
271
+ The web service may be monitored for OpenTelemetry by setting an environment variable **TELEMETRY_ENDPOINT** to a suitable trace collecting endpoint in an application like [Jaeger](https://www.jaegertracing.io/) (see also the [Translator SRI Jaeger-Demo](https://github.com/TranslatorSRI/Jaeger-demo)).
272
+
273
+ **Note:** the current system Docker (Compose) design only supports OpenTemplate tracing using the internal Jaeger container and may require further refinements to enable use of an external telemetry collector.
274
+
269
275
  ### Running the Web Service within Docker
270
276
 
271
277
  The Reasoner Validator web service may be run inside a docker container, using Docker Compose.
@@ -380,14 +380,6 @@
380
380
 
381
381
  **Description:** Knowledge graph node must have a 'id' key with a non-empty associated value!
382
382
 
383
- ### error.knowledge_graph.node.name.missing
384
-
385
- **Message:** Name is missing for node
386
-
387
- **Context:** identifier
388
-
389
- **Description:** Although TRAPI 1.4.0 states 'nullable: True', Translator user interface functionally requires that a non-empty 'name' property value must be specified in a knowledge graph node!
390
-
391
383
  ### error.knowledge_graph.node.category.missing
392
384
 
393
385
  **Message:** Category is missing for node
@@ -954,6 +946,14 @@
954
946
 
955
947
  **Description:** At least one query node is unused in the knowledge graph!
956
948
 
949
+ ### warning.knowledge_graph.node.name.missing
950
+
951
+ **Message:** Name is missing for node
952
+
953
+ **Context:** identifier
954
+
955
+ **Description:** Although TRAPI 1.4.0 states 'nullable: True', Translator user interface functionally requires that a non-empty 'name' property value ought to be specified in a knowledge graph node!
956
+
957
957
  ### warning.knowledge_graph.node.category.deprecated
958
958
 
959
959
  **Message:** Node has deprecated category
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "reasoner-validator"
3
- version = "3.9.2"
3
+ version = "3.9.4"
4
4
  description = "Validation tools for Reasoner API"
5
5
  authors = [
6
6
  "Richard Bruskiewich <richard.bruskiewich@delphinai.com>",
@@ -56,12 +56,22 @@ urllib3 = "^1.26.15"
56
56
  numpydoc = {version = "^1.5.0", optional = true}
57
57
  sphinx = {version = "^6.2.1", optional = true}
58
58
  myst-parser = {version = "^2.0.0", optional = true}
59
- fastapi = {version = "^0.68", optional = true}
60
- uvicorn = {version = "^0.15", optional = true}
59
+ fastapi = {version = "^0.85.0", optional = true}
60
+ uvicorn = {version = "*", optional = true}
61
61
  pytest-cov = {version = "^4.0.0"}
62
62
  pytest = {version = "^7.2.2"}
63
63
  sphinx-rtd-theme = {version = "^1.2.2", optional = true}
64
64
 
65
+ # for more pre-implemented OpenTelemetry instrumentations:
66
+ # https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation
67
+ httpx = {version = "^0.18.2", optional = true}
68
+
69
+ # exporting traces for jaeger
70
+ opentelemetry-exporter-otlp-proto-http = {version = "*", optional = true}
71
+
72
+ # instrumentation for fast api and httpx
73
+ opentelemetry-instrumentation-fastapi = {version = "*", optional = true}
74
+ opentelemetry-instrumentation-httpx = {version = "*", optional = true}
65
75
 
66
76
  [tool.poetry.urls]
67
77
  "Change Log" = "https://github.com/NCATSTranslator/reasoner-validator/blob/master/CHANGELOG.md"
@@ -69,7 +79,7 @@ sphinx-rtd-theme = {version = "^1.2.2", optional = true}
69
79
 
70
80
  [tool.poetry.extras]
71
81
  docs = ["numpydoc", "sphinx", "myst-parser", "sphinx-rtd-theme"]
72
- web = ["fastapi", "uvicorn"]
82
+ web = ["fastapi", "uvicorn", "httpx", "opentelemetry-exporter-otlp-proto-http", "opentelemetry-instrumentation-fastapi", "opentelemetry-instrumentation-httpx"]
73
83
 
74
84
  [tool.coverage.run]
75
85
  source = ["reasoner_validator"]
@@ -166,6 +166,8 @@ class BiolinkValidator(TRAPISchemaValidator, BMTWrapper):
166
166
  :param prefix: named context of the BiolinkValidator, used as a prefix in validation messages.
167
167
  :param trapi_version: Optional[str], caller specified Biolink Model version (default: None, use TRAPI 'latest')
168
168
  :param biolink_version: Optional[str], caller specified Biolink Model version (default: None, use BMT 'latest')
169
+ Note that a special biolink_version value string "suppress" disables full Biolink Model
170
+ validation by the validator (i.e. limits validation to superficial validation).
169
171
  :param target_provenance: Optional[Dict[str,str]], Dictionary of context ARA and KP for provenance validation
170
172
  :param strict_validation: Optional[bool] = None, if True, some tests validate as 'error'; False, simply issues
171
173
  'info' message; A value of 'None' uses the default value for specific graph contexts.
@@ -328,7 +330,7 @@ class BiolinkValidator(TRAPISchemaValidator, BMTWrapper):
328
330
  # UI team request (part of issue #35): really need names here
329
331
  if not ("name" in slots and slots["name"]):
330
332
  self.report(
331
- code="error.knowledge_graph.node.name.missing",
333
+ code="warning.knowledge_graph.node.name.missing",
332
334
  identifier=node_id
333
335
  )
334
336
 
@@ -298,12 +298,6 @@ error:
298
298
  $context:
299
299
  - identifier
300
300
  $description: "Knowledge graph node must have a 'id' key with a non-empty associated value!"
301
- name:
302
- missing:
303
- $message: "Name is missing for node"
304
- $context:
305
- - identifier
306
- $description: "Although TRAPI 1.4.0 states 'nullable: True', Translator user interface functionally requires that a non-empty 'name' property value must be specified in a knowledge graph node!"
307
301
  category:
308
302
  missing:
309
303
  $message: "Category is missing for node"
@@ -744,6 +738,13 @@ warning:
744
738
  - identifier
745
739
  $description: "At least one query node is unused in the knowledge graph!"
746
740
  node:
741
+ name:
742
+ missing:
743
+ $message: "Name is missing for node"
744
+ $context:
745
+ - identifier
746
+ $description: "Although TRAPI 1.4.0 states 'nullable: True', Translator user interface functionally requires that a non-empty 'name' property value ought to be specified in a knowledge graph node!"
747
+
747
748
  category:
748
749
  deprecated:
749
750
  $message: "Node has deprecated category"
@@ -1,6 +1,5 @@
1
1
  from typing import Optional, List, Dict
2
2
 
3
- import deprecation
4
3
  from bmt import Toolkit
5
4
 
6
5
  from reasoner_validator.biolink import (
@@ -10,8 +9,7 @@ from reasoner_validator.biolink import (
10
9
  )
11
10
 
12
11
  from reasoner_validator.report import TRAPIGraphType
13
- from reasoner_validator.trapi import TRAPI_1_3_0_SEMVER, TRAPI_1_4_0_BETA3_SEMVER, TRAPI_1_4_0_BETA4_SEMVER, \
14
- TRAPI_1_4_0_SEMVER, LATEST_TRAPI_RELEASE, LATEST_TRAPI_MAJOR_RELEASE_SEMVER
12
+ from reasoner_validator.trapi import LATEST_TRAPI_RELEASE, LATEST_TRAPI_MAJOR_RELEASE_SEMVER
15
13
  from reasoner_validator.trapi.mapping import MappingValidator, check_node_edge_mappings
16
14
  from reasoner_validator.versioning import SemVer, SemVerError, get_latest_version
17
15
  from reasoner_validator.sri.util import get_aliases
@@ -72,6 +70,29 @@ class TRAPIResponseValidator(BiolinkValidator):
72
70
  self._is_trapi_1_4 = True
73
71
  return self._is_trapi_1_4
74
72
 
73
+ def sanitize_workflow(self, response: Dict) -> Dict:
74
+ """
75
+ Workflows in TRAPI Responses cannot be validated further due to missing tags and None values.
76
+ This method is a temporary workaround to sanitize the query for additional validation.
77
+
78
+ :param response: Dict full TRAPI Response JSON object
79
+ :return: Dict, response with discretionary removal of content which
80
+ triggers (temporarily) unwarranted TRAPI validation failures
81
+ """
82
+ if 'workflow' in response and response['workflow']:
83
+ # a 'workflow' is a list of steps, which are JSON object specifications
84
+ workflow_steps: List[Dict] = response['workflow']
85
+ for step in workflow_steps:
86
+ if 'runner_parameters' in step and not step['runner_parameters']:
87
+ self.report("warning.trapi.response.workflow.runner_parameters.missing")
88
+ step.pop('runner_parameters')
89
+ if 'parameters' in step and not step['parameters']:
90
+ # There are some workflow types that have mandatory need for 'parameters'
91
+ # but this should be caught in a later schema validation step
92
+ self.report("warning.trapi.response.workflow.parameters.missing")
93
+ step.pop('parameters')
94
+ return response
95
+
75
96
  def check_compliance_of_trapi_response(
76
97
  self,
77
98
  response: Optional[Dict],
@@ -127,6 +148,8 @@ class TRAPIResponseValidator(BiolinkValidator):
127
148
  self.bmt = get_biolink_model_toolkit(biolink_version=response["biolink_version"])
128
149
  self.biolink_version = self.bmt.get_model_version()
129
150
 
151
+ response = self.sanitize_workflow(response)
152
+
130
153
  self.is_valid_trapi_query(instance=response, component="Response")
131
154
  if not self.has_critical():
132
155
 
@@ -2466,7 +2466,7 @@ def test_validate_biolink_curie_in_qualifiers(
2466
2466
  }
2467
2467
  }
2468
2468
  },
2469
- "error.knowledge_graph.node.name.missing"
2469
+ "warning.knowledge_graph.node.name.missing"
2470
2470
  ),
2471
2471
  (
2472
2472
  LATEST_BIOLINK_MODEL_VERSION,
@@ -880,9 +880,8 @@ def test_sample_graph(edges_limit: int, number_of_nodes_returned: int, number_of
880
880
  None,
881
881
  None,
882
882
  True,
883
- # removal of TRAPI Response sanitization now means
884
- # that this code snippet is JSON schema invalid
885
- "critical.trapi.validation"
883
+ # TRAPI Response workflow sanitization restored - this should pass
884
+ ""
886
885
  ),
887
886
  ( # Query 26 - We throw a full TRAPI JSON example here (taken directly from the
888
887
  # TRAPI implementation guidelines...) just for fun and profit
@@ -8,6 +8,7 @@ from itertools import product
8
8
  from json import dumps
9
9
 
10
10
  from reasoner_validator.trapi import TRAPISchemaValidator
11
+ from reasoner_validator.validator import TRAPIResponseValidator
11
12
 
12
13
  from tests import LATEST_TEST_RELEASES
13
14
 
@@ -78,3 +79,31 @@ def test_query_latest_trapi_workflow_properties(trapi_version: str, query: Dict)
78
79
 
79
80
  validator = TRAPISchemaValidator(trapi_version=trapi_version)
80
81
  validator.validate(query, "Query")
82
+
83
+
84
+ SAMPLE_QUERY_3 = {
85
+ "message": {
86
+ "knowledge_graph": None,
87
+ "query_graph": None,
88
+ "results": None,
89
+ },
90
+ "log_level": None,
91
+ "workflow": [
92
+ {
93
+ "id": "annotate_nodes",
94
+ "parameters": None,
95
+ "runner_parameters": None
96
+ },
97
+ {
98
+ "id": "lookup"
99
+ }
100
+ ]
101
+ }
102
+
103
+
104
+ def test_query_sanitize_response_workflow_properties():
105
+ """Test sanitization of flawed TRAPI Query workflow properties."""
106
+
107
+ validator = TRAPIResponseValidator()
108
+ response = validator.sanitize_workflow(SAMPLE_QUERY_3)
109
+ validator.validate(response, "Query")
@@ -25,6 +25,25 @@ logger = logging.getLogger(__name__)
25
25
  DEFAULT_TRAPI_POST_TIMEOUT = 600.0
26
26
 
27
27
 
28
+ TRAPI_1_3_0_SEMVER = SemVer.from_string("v1.3.0")
29
+ TRAPI_1_3_0: str = str(TRAPI_1_3_0_SEMVER)
30
+ TRAPI_1_4_0_BETA_SEMVER = SemVer.from_string("v1.4.0-beta")
31
+ TRAPI_1_4_0_BETA = str(TRAPI_1_4_0_BETA_SEMVER)
32
+ TRAPI_1_4_0_BETA2_SEMVER = SemVer.from_string("v1.4.0-beta2")
33
+ TRAPI_1_4_0_BETA3_SEMVER = SemVer.from_string("v1.4.0-beta3")
34
+ TRAPI_1_4_0_BETA4_SEMVER = SemVer.from_string("v1.4.0-beta4")
35
+ TRAPI_1_4_0_SEMVER = SemVer.from_string("v1.4.0")
36
+ TRAPI_1_4_0: str = str(TRAPI_1_4_0_SEMVER)
37
+ TRAPI_1_4_1_SEMVER = SemVer.from_string("v1.4.1")
38
+ TRAPI_1_4_1: str = str(TRAPI_1_4_1_SEMVER)
39
+ TRAPI_1_4_2_SEMVER = SemVer.from_string("v1.4.2")
40
+ TRAPI_1_4_2: str = str(TRAPI_1_4_2_SEMVER)
41
+ LATEST_TRAPI_RELEASE_SEMVER: SemVer = TRAPI_1_4_2_SEMVER
42
+ LATEST_TRAPI_RELEASE: str = TRAPI_1_4_2
43
+ LATEST_TRAPI_MAJOR_RELEASE_SEMVER: SemVer = SemVer.from_string("v1.4", core_fields=['major', 'minor'])
44
+ LATEST_TRAPI_MAJOR_RELEASE: str = str(LATEST_TRAPI_MAJOR_RELEASE_SEMVER)
45
+
46
+
28
47
  class TRAPIAccessError(RuntimeError):
29
48
  pass
30
49
 
@@ -355,22 +374,3 @@ class TRAPISchemaValidator(ValidationReporter):
355
374
  header += f" validating against TRAPI version " \
356
375
  f"'{str(self.get_trapi_version() if self.get_trapi_version() is not None else 'Default')}'"
357
376
  return header
358
-
359
-
360
- TRAPI_1_3_0_SEMVER = SemVer.from_string("v1.3.0")
361
- TRAPI_1_3_0: str = str(TRAPI_1_3_0_SEMVER)
362
- TRAPI_1_4_0_BETA_SEMVER = SemVer.from_string("v1.4.0-beta")
363
- TRAPI_1_4_0_BETA = str(TRAPI_1_4_0_BETA_SEMVER)
364
- TRAPI_1_4_0_BETA2_SEMVER = SemVer.from_string("v1.4.0-beta2")
365
- TRAPI_1_4_0_BETA3_SEMVER = SemVer.from_string("v1.4.0-beta3")
366
- TRAPI_1_4_0_BETA4_SEMVER = SemVer.from_string("v1.4.0-beta4")
367
- TRAPI_1_4_0_SEMVER = SemVer.from_string("v1.4.0")
368
- TRAPI_1_4_0: str = str(TRAPI_1_4_0_SEMVER)
369
- TRAPI_1_4_1_SEMVER = SemVer.from_string("v1.4.1")
370
- TRAPI_1_4_1: str = str(TRAPI_1_4_1_SEMVER)
371
- TRAPI_1_4_2_SEMVER = SemVer.from_string("v1.4.2")
372
- TRAPI_1_4_2: str = str(TRAPI_1_4_2_SEMVER)
373
- LATEST_TRAPI_RELEASE_SEMVER: SemVer = TRAPI_1_4_2_SEMVER
374
- LATEST_TRAPI_RELEASE: str = TRAPI_1_4_2
375
- LATEST_TRAPI_MAJOR_RELEASE_SEMVER: SemVer = SemVer.from_string("v1.4", core_fields=['major', 'minor'])
376
- LATEST_TRAPI_MAJOR_RELEASE: str = str(LATEST_TRAPI_MAJOR_RELEASE_SEMVER)