Skip to content

Commit f3346d9

Browse files
authored
feat: add Explicit bucket schemas API (#528)
1 parent d515488 commit f3346d9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+1908
-133
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
## 1.35.0 [unreleased]
22

3+
### Features
4+
1. [#528](https://github.com/influxdata/influxdb-client-python/pull/528): Add `BucketSchemasService` to manage explicit bucket schemas to enforce column names, tags, fields, and data types for your data
5+
36
### Bug Fixes
47
1. [#526](https://github.com/influxdata/influxdb-client-python/pull/526): Creating client instance from static configuration
58
1. [#531](https://github.com/influxdata/influxdb-client-python/pull/531): HTTP request return type for Management API [async/await]

examples/README.md

+8-3
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,23 @@
2222
- [query_response_to_json.py](query_response_to_json.py) - How to serialize Query response to JSON
2323
- [query_with_profilers.py](query_with_profilers.py) - How to process profilers output by callback
2424

25-
2625
## Management API
2726
- [buckets_management.py](buckets_management.py) - How to create, list and delete Buckets
2827
- [monitoring_and_alerting.py](monitoring_and_alerting.py) - How to create the Check with Slack notification.
2928
- [task_example.py](task_example.py) - How to create a Task by API
3029
- [templates_management.py](templates_management.py) - How to use Templates and Stack API
3130

32-
## Others
31+
## InfluxDB Cloud
32+
33+
:warning: The following examples are related to [InfluxDB Cloud](https://docs.influxdata.com/influxdb/cloud/) and not available on a local InfluxDB OSS instance.
34+
3335
- [influx_cloud.py](influx_cloud.py) - How to connect to InfluxDB 2 Cloud
36+
- [invokable_scripts.py](invokable_scripts.py) - How to use Invokable scripts Cloud API to create custom endpoints that query data
37+
- [bucket_schemas.py](bucket_schemas.py) - How to manage explicit bucket schemas to enforce column names, tags, fields, and data types for your data
38+
39+
## Others
3440
- [influxdb_18_example.py](influxdb_18_example.py) - How to connect to InfluxDB 1.8
3541
- [nanosecond_precision.py](nanosecond_precision.py) - How to use nanoseconds precision
36-
- [invokable_scripts.py](invokable_scripts.py) - How to use Invokable scripts Cloud API to create custom endpoints that query data
3742
- [connection_check.py](connection_check.py) - How to check connection configuration
3843

3944
## Asynchronous

examples/bucket_schemas.py

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
"""
2+
This example is related to `InfluxDB Cloud <https://docs.influxdata.com/influxdb/cloud/>`_ and not available
3+
on a local InfluxDB OSS instance.
4+
5+
How to manage explicit bucket schemas to enforce column names, tags, fields, and data types for your data.
6+
"""
7+
import datetime
8+
9+
from influxdb_client import InfluxDBClient, BucketSchemasService, PostBucketRequest, SchemaType, \
10+
MeasurementSchemaCreateRequest, MeasurementSchemaColumn, ColumnSemanticType, ColumnDataType, \
11+
MeasurementSchemaUpdateRequest
12+
13+
"""
14+
Define credentials
15+
"""
16+
influx_cloud_url = 'https://us-west-2-1.aws.cloud2.influxdata.com'
17+
influx_cloud_token = '...'
18+
org_name = '...'
19+
20+
with InfluxDBClient(url=influx_cloud_url, token=influx_cloud_token, org=org_name, debug=False) as client:
21+
uniqueId = str(datetime.datetime.now())
22+
org_id = client.organizations_api().find_organizations(org=org_name)[0].id
23+
bucket_schemas_api = BucketSchemasService(api_client=client.api_client)
24+
25+
"""
26+
Create a bucket with the schema_type flag set to explicit
27+
"""
28+
print("------- Create Bucket -------\n")
29+
created_bucket = client \
30+
.buckets_api() \
31+
.create_bucket(bucket=PostBucketRequest(name=f"my_schema_bucket_{uniqueId}",
32+
org_id=org_id,
33+
retention_rules=[],
34+
schema_type=SchemaType.EXPLICIT))
35+
print(created_bucket)
36+
37+
"""
38+
Sets the schema for a measurement: Usage CPU
39+
40+
[
41+
{"name": "time", "type": "timestamp"},
42+
{"name": "service", "type": "tag"},
43+
{"name": "host", "type": "tag"},
44+
{"name": "usage_user", "type": "field", "dataType": "float"},
45+
{"name": "usage_system", "type": "field", "dataType": "float"}
46+
]
47+
"""
48+
print("------- Create Schema -------\n")
49+
columns = [
50+
MeasurementSchemaColumn(name="time",
51+
type=ColumnSemanticType.TIMESTAMP),
52+
MeasurementSchemaColumn(name="service",
53+
type=ColumnSemanticType.TAG),
54+
MeasurementSchemaColumn(name="host",
55+
type=ColumnSemanticType.TAG),
56+
MeasurementSchemaColumn(name="usage_user",
57+
type=ColumnSemanticType.FIELD,
58+
data_type=ColumnDataType.FLOAT),
59+
MeasurementSchemaColumn(name="usage_system",
60+
type=ColumnSemanticType.FIELD,
61+
data_type=ColumnDataType.FLOAT)
62+
]
63+
create_request = MeasurementSchemaCreateRequest(name="usage_cpu", columns=columns)
64+
created_schema = bucket_schemas_api.create_measurement_schema(bucket_id=created_bucket.id,
65+
org_id=org_id,
66+
measurement_schema_create_request=create_request)
67+
print(created_bucket)
68+
69+
"""
70+
Lists the Schemas
71+
"""
72+
print("\n------- Lists the Schemas -------\n")
73+
measurement_schemas = bucket_schemas_api.get_measurement_schemas(bucket_id=created_bucket.id).measurement_schemas
74+
print("\n".join([f"---\n ID: {ms.id}\n Name: {ms.name}\n Columns: {ms.columns}" for ms in measurement_schemas]))
75+
print("---")
76+
77+
"""
78+
Update a bucket schema
79+
"""
80+
print("------- Update a bucket schema -------\n")
81+
columns.append(MeasurementSchemaColumn(name="usage_total",
82+
type=ColumnSemanticType.FIELD,
83+
data_type=ColumnDataType.FLOAT))
84+
update_request = MeasurementSchemaUpdateRequest(columns=columns)
85+
updated_schema = bucket_schemas_api.update_measurement_schema(bucket_id=created_bucket.id,
86+
measurement_id=created_schema.id,
87+
measurement_schema_update_request=update_request)
88+
print(updated_schema)
89+
90+
"""
91+
Delete previously created bucket
92+
"""
93+
print("------- Delete Bucket -------\n")
94+
client.buckets_api().delete_bucket(created_bucket)
95+
print(f" successfully deleted bucket: {created_bucket.name}")

examples/invokable_scripts.py

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
"""
2+
This example is related to `InfluxDB Cloud <https://docs.influxdata.com/influxdb/cloud/>`_ and not available
3+
on a local InfluxDB OSS instance.
4+
25
How to use Invokable scripts Cloud API to create custom endpoints that query data
36
"""
47
import datetime

influxdb_client/__init__.py

+8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
# import apis into sdk package
1818
from influxdb_client.service.authorizations_service import AuthorizationsService
1919
from influxdb_client.service.backup_service import BackupService
20+
from influxdb_client.service.bucket_schemas_service import BucketSchemasService
2021
from influxdb_client.service.buckets_service import BucketsService
2122
from influxdb_client.service.cells_service import CellsService
2223
from influxdb_client.service.checks_service import ChecksService
@@ -100,6 +101,8 @@
100101
from influxdb_client.domain.check_status_level import CheckStatusLevel
101102
from influxdb_client.domain.check_view_properties import CheckViewProperties
102103
from influxdb_client.domain.checks import Checks
104+
from influxdb_client.domain.column_data_type import ColumnDataType
105+
from influxdb_client.domain.column_semantic_type import ColumnSemanticType
103106
from influxdb_client.domain.conditional_expression import ConditionalExpression
104107
from influxdb_client.domain.config import Config
105108
from influxdb_client.domain.constant_variable_properties import ConstantVariableProperties
@@ -167,6 +170,11 @@
167170
from influxdb_client.domain.logs import Logs
168171
from influxdb_client.domain.map_variable_properties import MapVariableProperties
169172
from influxdb_client.domain.markdown_view_properties import MarkdownViewProperties
173+
from influxdb_client.domain.measurement_schema import MeasurementSchema
174+
from influxdb_client.domain.measurement_schema_column import MeasurementSchemaColumn
175+
from influxdb_client.domain.measurement_schema_create_request import MeasurementSchemaCreateRequest
176+
from influxdb_client.domain.measurement_schema_list import MeasurementSchemaList
177+
from influxdb_client.domain.measurement_schema_update_request import MeasurementSchemaUpdateRequest
170178
from influxdb_client.domain.member_assignment import MemberAssignment
171179
from influxdb_client.domain.member_expression import MemberExpression
172180
from influxdb_client.domain.metadata_backup import MetadataBackup

influxdb_client/client/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# import apis into api package
1616
from influxdb_client.service.authorizations_service import AuthorizationsService
1717
from influxdb_client.service.backup_service import BackupService
18+
from influxdb_client.service.bucket_schemas_service import BucketSchemasService
1819
from influxdb_client.service.buckets_service import BucketsService
1920
from influxdb_client.service.cells_service import CellsService
2021
from influxdb_client.service.checks_service import ChecksService

influxdb_client/client/_base.py

-7
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,6 @@ def __init__(self, url, token, debug=None, timeout=10_000, enable_gzip=False, or
9898
self.profilers = kwargs.get('profilers', None)
9999
pass
100100

101-
def _version(self, response) -> str:
102-
if response is not None and len(response) >= 3:
103-
if 'X-Influxdb-Version' in response[2]:
104-
return response[2]['X-Influxdb-Version']
105-
106-
return "unknown"
107-
108101
@classmethod
109102
def _from_config_file(cls, config_file: str = "config.ini", debug=None, enable_gzip=False, **kwargs):
110103
config = configparser.ConfigParser()

influxdb_client/client/bucket_api.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def create_bucket(self, bucket=None, bucket_name=None, org_id=None, retention_ru
2222
description=None, org=None) -> Bucket:
2323
"""Create a bucket.
2424
25-
:param Bucket bucket: bucket to create
25+
:param Bucket|PostBucketRequest bucket: bucket to create
2626
:param bucket_name: bucket name
2727
:param description: bucket description
2828
:param org_id: org_id

influxdb_client/client/influxdb_client.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,17 @@ def version(self) -> str:
407407

408408
response = ping_service.get_ping_with_http_info(_return_http_data_only=False)
409409

410-
return self._version(response)
410+
return ping_service.response_header(response)
411+
412+
def build(self) -> str:
413+
"""
414+
Return the build type of the connected InfluxDB Server.
415+
416+
:return: The type of InfluxDB build.
417+
"""
418+
ping_service = PingService(self.api_client)
419+
420+
return ping_service.build_type()
411421

412422
def ready(self) -> Ready:
413423
"""

influxdb_client/client/influxdb_client_async.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,17 @@ async def version(self) -> str:
251251
ping_service = PingService(self.api_client)
252252

253253
response = await ping_service.get_ping_async(_return_http_data_only=False)
254-
return self._version(response)
254+
return ping_service.response_header(response)
255+
256+
async def build(self) -> str:
257+
"""
258+
Return the build type of the connected InfluxDB Server.
259+
260+
:return: The type of InfluxDB build.
261+
"""
262+
ping_service = PingService(self.api_client)
263+
264+
return await ping_service.build_type_async()
255265

256266
def query_api(self, query_options: QueryOptions = QueryOptions()) -> QueryApiAsync:
257267
"""

influxdb_client/client/warnings.py

+21
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,24 @@ def print_warning(query: str):
2929
- https://docs.influxdata.com/flux/latest/stdlib/influxdata/influxdb/schema/fieldsascols/
3030
"""
3131
warnings.warn(message, MissingPivotFunction)
32+
33+
34+
class CloudOnlyWarning(UserWarning):
35+
"""User warning about availability only on the InfluxDB Cloud."""
36+
37+
@staticmethod
38+
def print_warning(api_name: str, doc_url: str):
39+
"""Print warning about availability only on the InfluxDB Cloud."""
40+
message = f"""The '{api_name}' is available only on the InfluxDB Cloud.
41+
42+
For more info see:
43+
- {doc_url}
44+
- https://docs.influxdata.com/influxdb/cloud/
45+
46+
You can disable this warning by:
47+
import warnings
48+
from influxdb_client.client.warnings import CloudOnlyWarning
49+
50+
warnings.simplefilter("ignore", CloudOnlyWarning)
51+
"""
52+
warnings.warn(message, CloudOnlyWarning)

influxdb_client/client/write/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# import apis into api package
1616
from influxdb_client.service.authorizations_service import AuthorizationsService
1717
from influxdb_client.service.backup_service import BackupService
18+
from influxdb_client.service.bucket_schemas_service import BucketSchemasService
1819
from influxdb_client.service.buckets_service import BucketsService
1920
from influxdb_client.service.cells_service import CellsService
2021
from influxdb_client.service.checks_service import ChecksService

influxdb_client/domain/__init__.py

+7
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
from influxdb_client.domain.check_status_level import CheckStatusLevel
5757
from influxdb_client.domain.check_view_properties import CheckViewProperties
5858
from influxdb_client.domain.checks import Checks
59+
from influxdb_client.domain.column_data_type import ColumnDataType
60+
from influxdb_client.domain.column_semantic_type import ColumnSemanticType
5961
from influxdb_client.domain.conditional_expression import ConditionalExpression
6062
from influxdb_client.domain.config import Config
6163
from influxdb_client.domain.constant_variable_properties import ConstantVariableProperties
@@ -123,6 +125,11 @@
123125
from influxdb_client.domain.logs import Logs
124126
from influxdb_client.domain.map_variable_properties import MapVariableProperties
125127
from influxdb_client.domain.markdown_view_properties import MarkdownViewProperties
128+
from influxdb_client.domain.measurement_schema import MeasurementSchema
129+
from influxdb_client.domain.measurement_schema_column import MeasurementSchemaColumn
130+
from influxdb_client.domain.measurement_schema_create_request import MeasurementSchemaCreateRequest
131+
from influxdb_client.domain.measurement_schema_list import MeasurementSchemaList
132+
from influxdb_client.domain.measurement_schema_update_request import MeasurementSchemaUpdateRequest
126133
from influxdb_client.domain.member_assignment import MemberAssignment
127134
from influxdb_client.domain.member_expression import MemberExpression
128135
from influxdb_client.domain.metadata_backup import MetadataBackup
+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# coding: utf-8
2+
3+
"""
4+
InfluxDB OSS API Service.
5+
6+
The InfluxDB v2 API provides a programmatic interface for all interactions with InfluxDB. Access the InfluxDB API using the `/api/v2/` endpoint. # noqa: E501
7+
8+
OpenAPI spec version: 2.0.0
9+
Generated by: https://openapi-generator.tech
10+
"""
11+
12+
13+
import pprint
14+
import re # noqa: F401
15+
16+
17+
class ColumnDataType(object):
18+
"""NOTE: This class is auto generated by OpenAPI Generator.
19+
20+
Ref: https://openapi-generator.tech
21+
22+
Do not edit the class manually.
23+
"""
24+
25+
"""
26+
allowed enum values
27+
"""
28+
INTEGER = "integer"
29+
FLOAT = "float"
30+
BOOLEAN = "boolean"
31+
STRING = "string"
32+
UNSIGNED = "unsigned"
33+
34+
"""
35+
Attributes:
36+
openapi_types (dict): The key is attribute name
37+
and the value is attribute type.
38+
attribute_map (dict): The key is attribute name
39+
and the value is json key in definition.
40+
"""
41+
openapi_types = {
42+
}
43+
44+
attribute_map = {
45+
}
46+
47+
def __init__(self): # noqa: E501,D401,D403
48+
"""ColumnDataType - a model defined in OpenAPI.""" # noqa: E501 self.discriminator = None
49+
50+
def to_dict(self):
51+
"""Return the model properties as a dict."""
52+
result = {}
53+
54+
for attr, _ in self.openapi_types.items():
55+
value = getattr(self, attr)
56+
if isinstance(value, list):
57+
result[attr] = list(map(
58+
lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
59+
value
60+
))
61+
elif hasattr(value, "to_dict"):
62+
result[attr] = value.to_dict()
63+
elif isinstance(value, dict):
64+
result[attr] = dict(map(
65+
lambda item: (item[0], item[1].to_dict())
66+
if hasattr(item[1], "to_dict") else item,
67+
value.items()
68+
))
69+
else:
70+
result[attr] = value
71+
72+
return result
73+
74+
def to_str(self):
75+
"""Return the string representation of the model."""
76+
return pprint.pformat(self.to_dict())
77+
78+
def __repr__(self):
79+
"""For `print` and `pprint`."""
80+
return self.to_str()
81+
82+
def __eq__(self, other):
83+
"""Return true if both objects are equal."""
84+
if not isinstance(other, ColumnDataType):
85+
return False
86+
87+
return self.__dict__ == other.__dict__
88+
89+
def __ne__(self, other):
90+
"""Return true if both objects are not equal."""
91+
return not self == other

0 commit comments

Comments
 (0)