Skip to content

Commit 856cca4

Browse files
authored
feat: Org parameter can be specified as ID, Name or Organization Object (influxdata#264)
1 parent 925e7cd commit 856cca4

File tree

10 files changed

+139
-44
lines changed

10 files changed

+139
-44
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
## 1.19.0 [unreleased]
22

3+
### Features
4+
1. [#264](https://github.com/influxdata/influxdb-client-python/pull/264): Org parameter can be specified as ID, Name or Organization Object [write, query]
5+
6+
### Deprecated
7+
1. [#264](https://github.com/influxdata/influxdb-client-python/pull/264): Deprecated `org_id` options BucketsApi.create_bucket in favor of `org` parameter
8+
39
## 1.18.0 [2021-06-04]
410

511
### Breaking Changes

examples/buckets_management.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,19 @@
99
"""
1010
url = "http://localhost:8086"
1111
token = "my-token"
12+
org = "my-org"
1213

1314
with InfluxDBClient(url=url, token=token) as client:
1415
buckets_api = client.buckets_api()
1516

16-
"""
17-
The Bucket API uses as a parameter the Organization ID. We have to retrieve ID by Organization API.
18-
"""
19-
org_name = "my-org"
20-
org = client.organizations_api().find_organizations(org=org_name)[0]
21-
2217
"""
2318
Create Bucket with retention policy set to 3600 seconds and name "bucket-by-python"
2419
"""
2520
print(f"------- Create -------\n")
2621
retention_rules = BucketRetentionRules(type="expire", every_seconds=3600)
2722
created_bucket = buckets_api.create_bucket(bucket_name="bucket-by-python",
2823
retention_rules=retention_rules,
29-
org_id=org.id)
24+
org=org)
3025
print(created_bucket)
3126

3227
"""

influxdb_client/client/bucket_api.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
All buckets have a retention policy, a duration of time that each data point persists.
55
A bucket belongs to an organization.
66
"""
7-
7+
import warnings
88

99
from influxdb_client import BucketsService, Bucket, PostBucketRequest
10+
from influxdb_client.client.util.helpers import get_org_query_param
1011

1112

1213
class BucketsApi(object):
@@ -18,15 +19,18 @@ def __init__(self, influxdb_client):
1819
self._buckets_service = BucketsService(influxdb_client.api_client)
1920

2021
def create_bucket(self, bucket=None, bucket_name=None, org_id=None, retention_rules=None,
21-
description=None) -> Bucket:
22+
description=None, org=None) -> Bucket:
2223
"""Create a bucket.
2324
24-
:param Bucket bucket: bucket to create (required)
25+
:param Bucket bucket: bucket to create
2526
:param bucket_name: bucket name
2627
:param description: bucket description
2728
:param org_id: org_id
2829
:param bucket_name: bucket name
2930
:param retention_rules: retention rules array or single BucketRetentionRules
31+
:param str, Organization org: specifies the organization for create the bucket;
32+
take the ID, Name or Organization;
33+
if it's not specified then is used default from client.org.
3034
:return: Bucket
3135
If the method is called asynchronously,
3236
returns the request thread.
@@ -41,11 +45,16 @@ def create_bucket(self, bucket=None, bucket_name=None, org_id=None, retention_ru
4145
else:
4246
rules.append(retention_rules)
4347

48+
if org_id is not None:
49+
warnings.warn("org_id is deprecated; use org", DeprecationWarning)
50+
4451
if bucket is None:
4552
bucket = PostBucketRequest(name=bucket_name,
4653
retention_rules=rules,
4754
description=description,
48-
org_id=self._influxdb_client.org if org_id is None else org_id)
55+
org_id=get_org_query_param(org=(org_id if org is None else org),
56+
client=self._influxdb_client,
57+
required_id=True))
4958

5059
return self._buckets_service.post_buckets(post_bucket_request=bucket)
5160

influxdb_client/client/query_api.py

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from influxdb_client.client.flux_csv_parser import FluxCsvParser, FluxSerializationMode
1717
from influxdb_client.client.flux_table import FluxTable, FluxRecord
1818
from influxdb_client.client.util.date_utils import get_date_helper
19+
from influxdb_client.client.util.helpers import get_org_query_param
1920

2021

2122
class QueryOptions(object):
@@ -51,14 +52,15 @@ def query_csv(self, query: str, org=None, dialect: Dialect = default_dialect, pa
5152
Execute the Flux query and return results as a CSV iterator. Each iteration returns a row of the CSV file.
5253
5354
:param query: a Flux query
54-
:param org: organization name (optional if already specified in InfluxDBClient)
55+
:param str, Organization org: specifies the organization for executing the query;
56+
take the ID, Name or Organization;
57+
if it's not specified then is used default from client.org.
5558
:param dialect: csv dialect format
5659
:param params: bind parameters
5760
:return: The returned object is an iterator. Each iteration returns a row of the CSV file
5861
(which can span multiple input lines).
5962
"""
60-
if org is None:
61-
org = self._influxdb_client.org
63+
org = self._org_param(org)
6264
response = self._query_api.post_query(org=org, query=self._create_query(query, dialect, params),
6365
async_req=False, _preload_content=False)
6466

@@ -69,13 +71,14 @@ def query_raw(self, query: str, org=None, dialect=default_dialect, params: dict
6971
Execute synchronous Flux query and return result as raw unprocessed result as a str.
7072
7173
:param query: a Flux query
72-
:param org: organization name (optional if already specified in InfluxDBClient)
74+
:param str, Organization org: specifies the organization for executing the query;
75+
take the ID, Name or Organization;
76+
if it's not specified then is used default from client.org.
7377
:param dialect: csv dialect format
7478
:param params: bind parameters
7579
:return: str
7680
"""
77-
if org is None:
78-
org = self._influxdb_client.org
81+
org = self._org_param(org)
7982
result = self._query_api.post_query(org=org, query=self._create_query(query, dialect, params), async_req=False,
8083
_preload_content=False)
8184

@@ -86,12 +89,13 @@ def query(self, query: str, org=None, params: dict = None) -> List['FluxTable']:
8689
Execute synchronous Flux query and return result as a List['FluxTable'].
8790
8891
:param query: the Flux query
89-
:param org: organization name (optional if already specified in InfluxDBClient)
92+
:param str, Organization org: specifies the organization for executing the query;
93+
take the ID, Name or Organization;
94+
if it's not specified then is used default from client.org.
9095
:param params: bind parameters
9196
:return:
9297
"""
93-
if org is None:
94-
org = self._influxdb_client.org
98+
org = self._org_param(org)
9599

96100
response = self._query_api.post_query(org=org, query=self._create_query(query, self.default_dialect, params),
97101
async_req=False, _preload_content=False, _return_http_data_only=False)
@@ -108,12 +112,13 @@ def query_stream(self, query: str, org=None, params: dict = None) -> Generator['
108112
Execute synchronous Flux query and return stream of FluxRecord as a Generator['FluxRecord'].
109113
110114
:param query: the Flux query
111-
:param org: organization name (optional if already specified in InfluxDBClient)
115+
:param str, Organization org: specifies the organization for executing the query;
116+
take the ID, Name or Organization;
117+
if it's not specified then is used default from client.org.
112118
:param params: bind parameters
113119
:return:
114120
"""
115-
if org is None:
116-
org = self._influxdb_client.org
121+
org = self._org_param(org)
117122

118123
response = self._query_api.post_query(org=org, query=self._create_query(query, self.default_dialect, params),
119124
async_req=False, _preload_content=False, _return_http_data_only=False)
@@ -129,7 +134,9 @@ def query_data_frame(self, query: str, org=None, data_frame_index: List[str] = N
129134
Note that if a query returns more then one table than the client generates a DataFrame for each of them.
130135
131136
:param query: the Flux query
132-
:param org: organization name (optional if already specified in InfluxDBClient)
137+
:param str, Organization org: specifies the organization for executing the query;
138+
take the ID, Name or Organization;
139+
if it's not specified then is used default from client.org.
133140
:param data_frame_index: the list of columns that are used as DataFrame index
134141
:param params: bind parameters
135142
:return:
@@ -153,13 +160,14 @@ def query_data_frame_stream(self, query: str, org=None, data_frame_index: List[s
153160
Note that if a query returns more then one table than the client generates a DataFrame for each of them.
154161
155162
:param query: the Flux query
156-
:param org: organization name (optional if already specified in InfluxDBClient)
163+
:param str, Organization org: specifies the organization for executing the query;
164+
take the ID, Name or Organization;
165+
if it's not specified then is used default from client.org.
157166
:param data_frame_index: the list of columns that are used as DataFrame index
158167
:param params: bind parameters
159168
:return:
160169
"""
161-
if org is None:
162-
org = self._influxdb_client.org
170+
org = self._org_param(org)
163171

164172
response = self._query_api.post_query(org=org, query=self._create_query(query, self.default_dialect, params),
165173
async_req=False, _preload_content=False, _return_http_data_only=False)
@@ -187,6 +195,9 @@ def _create_query(self, query, dialect=default_dialect, params: dict = None):
187195

188196
return q
189197

198+
def _org_param(self, org):
199+
return get_org_query_param(org=org, client=self._influxdb_client)
200+
190201
@staticmethod
191202
def _params_to_extern_ast(params: dict) -> List['OptionStatement']:
192203

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""Functions to share utility across client classes."""
2+
from influxdb_client.rest import ApiException
3+
4+
5+
def _is_id(value):
6+
"""
7+
Check if the value is valid InfluxDB ID.
8+
9+
:param value: to check
10+
:return: True if provided parameter is valid InfluxDB ID.
11+
"""
12+
if value and len(value) == 16:
13+
try:
14+
int(value, 16)
15+
return True
16+
except ValueError:
17+
return False
18+
return False
19+
20+
21+
def get_org_query_param(org, client, required_id=False):
22+
"""
23+
Get required type of Org query parameter.
24+
25+
:param str, Organization org: value provided as a parameter into API (optional)
26+
:param InfluxDBClient client: with default value for Org parameter
27+
:param bool required_id: true if the query param has to be a ID
28+
:return: request type of org query parameter or None
29+
"""
30+
_org = client.org if org is None else org
31+
if 'Organization' in type(_org).__name__:
32+
_org = _org.id
33+
if required_id and _org and not _is_id(_org):
34+
try:
35+
return client.organizations_api().find_organizations(org=_org)[0].id
36+
except ApiException:
37+
return None
38+
39+
return _org

influxdb_client/client/write_api.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from rx.subject import Subject
1717

1818
from influxdb_client import WritePrecision, WriteService
19+
from influxdb_client.client.util.helpers import get_org_query_param
1920
from influxdb_client.client.write.dataframe_serializer import data_frame_to_list_of_points
2021
from influxdb_client.client.write.point import Point, DEFAULT_WRITE_PRECISION
2122
from influxdb_client.client.write.retry import WritesRetry
@@ -221,8 +222,9 @@ def write(self, bucket: str, org: str = None,
221222
"""
222223
Write time-series data into InfluxDB.
223224
224-
:param str org: specifies the destination organization for writes; take either the ID or Name interchangeably;
225-
if both orgID and org are specified, org takes precedence. (required)
225+
:param str, Organization org: specifies the destination organization for writes;
226+
take the ID, Name or Organization;
227+
if it's not specified then is used default from client.org.
226228
:param str bucket: specifies the destination bucket for writes (required)
227229
:param WritePrecision write_precision: specifies the precision for the unix timestamps within
228230
the body line-protocol. The precision specified on a Point has precedes
@@ -231,8 +233,7 @@ def write(self, bucket: str, org: str = None,
231233
:key data_frame_measurement_name: name of measurement for writing Pandas DataFrame
232234
:key data_frame_tag_columns: list of DataFrame columns which are tags, rest columns will be fields
233235
"""
234-
if org is None:
235-
org = self._influxdb_client.org
236+
org = get_org_query_param(org=org, client=self._influxdb_client)
236237

237238
if self._point_settings.defaultTags and record is not None:
238239
for key, val in self._point_settings.defaultTags.items():

tests/base_test.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,15 @@ def tearDown(self) -> None:
4141

4242
def create_test_bucket(self):
4343
bucket_name = generate_bucket_name()
44-
bucket = self.buckets_api.create_bucket(bucket_name=bucket_name, org_id=self.my_organization.id,
44+
bucket = self.buckets_api.create_bucket(bucket_name=bucket_name, org=self.my_organization,
4545
description=bucket_name + "description")
4646
return bucket
4747

4848
def delete_test_bucket(self, bucket):
4949
return self.buckets_api.delete_bucket(bucket)
5050

5151
def find_my_org(self) -> Organization:
52-
org_api = influxdb_client.service.organizations_service.OrganizationsService(self.api_client)
53-
orgs = org_api.get_orgs()
54-
for org in orgs.orgs:
55-
if org.name == self.org:
56-
return org
52+
return self.client.organizations_api().find_organizations(org=self.org)[0]
5753

5854
@staticmethod
5955
def log(args):

tests/test_AuthorizationApi.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def test_createAuthorizationBucket(self):
8282
organization = self.client.organizations_api().create_organization(self.generate_name("Auth Organization"))
8383
bucket = self.client.buckets_api().create_bucket(bucket_name=self.generate_name("Auth Bucket"),
8484
retention_rules=BaseTest.retention_rule(),
85-
org_id=self.organization.id)
85+
org=self.organization)
8686
resource = PermissionResource(org_id=organization.id, type="buckets", id=bucket.id)
8787
create_bucket = Permission(action="read", resource=resource)
8888
delete_bucket = Permission(action="write", resource=resource)

tests/test_BucketsApi.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def test_create_delete_bucket(self):
2222
my_org = self.find_my_org()
2323

2424
bucket_name = generate_bucket_name()
25-
my_bucket = self.buckets_api.create_bucket(bucket_name=bucket_name, org_id=my_org.id)
25+
my_bucket = self.buckets_api.create_bucket(bucket_name=bucket_name, org=my_org)
2626
self.assertEqual(my_bucket.name, bucket_name)
2727
self.assertEqual(my_bucket.org_id, my_org.id)
2828
print(my_bucket)
@@ -41,7 +41,7 @@ def test_find_by_name(self):
4141
my_org = self.find_my_org()
4242

4343
bucket_name = generate_bucket_name()
44-
my_bucket = self.buckets_api.create_bucket(bucket_name=bucket_name, org_id=my_org.id)
44+
my_bucket = self.buckets_api.create_bucket(bucket_name=bucket_name, org=my_org)
4545

4646
bucket_by_name = self.buckets_api.find_bucket_by_name(bucket_name=my_bucket.name)
4747

@@ -58,7 +58,7 @@ def test_create_bucket_retention(self):
5858

5959
retention = BucketRetentionRules(type="expire", every_seconds=3600)
6060
desc = "bucket with retention"
61-
my_bucket = self.buckets_api.create_bucket(bucket_name=bucket_name, org_id=my_org.id,
61+
my_bucket = self.buckets_api.create_bucket(bucket_name=bucket_name, org=my_org,
6262
retention_rules=retention, description=desc)
6363

6464
self.assertEqual(my_bucket.description, desc)
@@ -76,7 +76,7 @@ def test_create_bucket_retention_list(self):
7676
retention.type = "expire"
7777
ret_list.append(retention)
7878

79-
my_bucket = self.buckets_api.create_bucket(bucket_name=bucket_name, org_id=my_org.id,
79+
my_bucket = self.buckets_api.create_bucket(bucket_name=bucket_name, org=my_org,
8080
retention_rules=ret_list)
8181

8282
self.assertEqual(my_bucket.name, bucket_name)
@@ -89,8 +89,8 @@ def test_pagination(self):
8989
size = len(buckets)
9090

9191
# create 2 buckets
92-
self.buckets_api.create_bucket(bucket_name=generate_bucket_name(), org_id=my_org.id)
93-
self.buckets_api.create_bucket(bucket_name=generate_bucket_name(), org_id=my_org.id)
92+
self.buckets_api.create_bucket(bucket_name=generate_bucket_name(), org=my_org)
93+
self.buckets_api.create_bucket(bucket_name=generate_bucket_name(), org=my_org)
9494

9595
buckets = self.buckets_api.find_buckets().buckets
9696
self.assertEqual(size + 2, len(buckets))

tests/test_Helpers.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from influxdb_client import InfluxDBClient, Organization
2+
# noinspection PyProtectedMember
3+
from influxdb_client.client.util.helpers import get_org_query_param, _is_id
4+
from tests.base_test import BaseTest
5+
6+
7+
class HelpersTest(BaseTest):
8+
9+
def test_is_id(self):
10+
self.assertTrue(_is_id("ffffffffffffffff"))
11+
self.assertTrue(_is_id("020f755c3c082000"))
12+
self.assertTrue(_is_id("ca55e77eca55e77e"))
13+
self.assertTrue(_is_id("02def021097c6000"))
14+
self.assertFalse(_is_id("gggggggggggggggg"))
15+
self.assertFalse(_is_id("abc"))
16+
self.assertFalse(_is_id("abcdabcdabcdabcd0"))
17+
self.assertFalse(_is_id("020f75"))
18+
self.assertFalse(_is_id("020f755c3c082000aaa"))
19+
self.assertFalse(_is_id(None))
20+
21+
def test_organization_as_query_param(self):
22+
organization = Organization(id="org-id", name="org-name")
23+
org = get_org_query_param(organization, self.client)
24+
self.assertEqual("org-id", org)
25+
26+
def test_required_id(self):
27+
org = get_org_query_param(None, self.client, required_id=True)
28+
self.assertEqual(self.my_organization.id, org)
29+
30+
def test_required_id_not_exist(self):
31+
org = get_org_query_param("not_exist_name", self.client, required_id=True)
32+
self.assertIsNone(org)
33+
34+
def test_both_none(self):
35+
self.client.close()
36+
self.client = InfluxDBClient(url=self.client.url, token="my-token")
37+
org = get_org_query_param(None, self.client)
38+
self.assertIsNone(org)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy