diff --git a/CHANGELOG.md b/CHANGELOG.md index ca6775c6..8d5ac8fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ 1. [#714](https://github.com/influxdata/influxdb-client-python/pull/714): Implement `WriteApi.flush()` to force pending batch writes without disposing the API (mirrors C#/Java batch writer). 1. [#715](https://github.com/influxdata/influxdb-client-python/pull/715): Accept numeric zero for `RangeThreshold.min`/`max` and greater/lesser `value` (identity checks vs `None`, not truthiness); cover create-check serialization. 1. [#720](https://github.com/influxdata/influxdb-client-python/pull/720): Prevent the `api_client` class from raising exceptions while the Python interpreter clears the client state during shutdown. +1. [#723](https://github.com/influxdata/influxdb-client-python/pull/723): Export public names using generated `__all__` array in `__init__.py` as per reference documentation. ## 1.50.0 [2026-01-23] diff --git a/examples/asynchronous_batching.py b/examples/asynchronous_batching.py index 722ca233..df0c7b81 100644 --- a/examples/asynchronous_batching.py +++ b/examples/asynchronous_batching.py @@ -2,6 +2,8 @@ How to use RxPY to prepare batches for asyncio client. """ import asyncio +import logging +from datetime import datetime from csv import DictReader import reactivex as rx @@ -11,6 +13,8 @@ from influxdb_client import Point from influxdb_client.client.influxdb_client_async import InfluxDBClientAsync +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) def csv_to_generator(csv_file_path): """ @@ -39,7 +43,10 @@ async def async_write(batch): """ Prepare async task """ - await write_api.write(bucket='my-bucket', record=batch) + try: + await write_api.write(bucket='my-bucket', record=batch) + except (asyncio.CancelledError, asyncio.TimeoutError) as exc: + logger.warning(f"[{datetime.now()}] on batch write caught exception: {type(exc).__name__}") return batch """ @@ -55,8 +62,8 @@ async def async_write(batch): """ Write batches by subscribing to Rx generator """ - batches.subscribe(on_next=lambda batch: print(f'Written batch... {len(batch)}'), - on_error=lambda ex: print(f'Unexpected error: {ex}'), + batches.subscribe(on_next=lambda batch: logger.info(f'[{datetime.now()}] Written batch... {len(batch)}'), + on_error=lambda ex: done.set_exception(ex), on_completed=lambda: done.set_result(0), scheduler=AsyncIOScheduler(asyncio.get_event_loop())) """ diff --git a/influxdb_client/__init__.py b/influxdb_client/__init__.py index a1009511..1fd36a84 100644 --- a/influxdb_client/__init__.py +++ b/influxdb_client/__init__.py @@ -394,3 +394,88 @@ from influxdb_client.version import VERSION __version__ = VERSION + +# following list generated with... +# $ grep "^from.*import.*" influxdb_client/__init__.py | awk '{ print $4 $5 }' | sed "s/^/'/" | sed "s/$/',/" | tr '\n' ' ' +# Some small anomalies like inclusion of absolute_import and multiple imports from same module corrected by hand + +__all__ = ['AuthorizationsService', 'BackupService', 'BucketSchemasService', 'BucketsService', 'CellsService', + 'ChecksService', 'ConfigService', 'DBRPsService', 'DashboardsService', 'DeleteService', 'HealthService', + 'InvokableScriptsService', 'LabelsService', 'LegacyAuthorizationsService', 'MetricsService', + 'NotificationEndpointsService', 'NotificationRulesService', 'OrganizationsService', 'PingService', + 'QueryService', 'ReadyService', 'RemoteConnectionsService', 'ReplicationsService', 'ResourcesService', + 'RestoreService', 'RoutesService', 'RulesService', 'ScraperTargetsService', 'SecretsService', 'SetupService', + 'SigninService', 'SignoutService', 'SourcesService', 'TasksService', 'TelegrafPluginsService', + 'TelegrafsService', 'TemplatesService', 'UsersService', 'VariablesService', 'ViewsService', 'WriteService', + 'Configuration', 'ASTResponse', 'AddResourceMemberRequestBody', 'AnalyzeQueryResponse', + 'AnalyzeQueryResponseErrors', 'ArrayExpression', 'Authorization', 'AuthorizationPostRequest', + 'AuthorizationUpdateRequest', 'Authorizations', 'Axes', 'Axis', 'AxisScale', 'BadStatement', + 'BandViewProperties', 'BinaryExpression', 'Block', 'BooleanLiteral', 'Bucket', 'BucketLinks', + 'BucketMetadataManifest', 'BucketRetentionRules', 'BucketShardMapping', 'Buckets', + 'BuilderAggregateFunctionType', 'BuilderConfig', 'BuilderConfigAggregateWindow', 'BuilderFunctionsType', + 'BuilderTagsType', 'BuiltinStatement', 'CallExpression', 'Cell', 'CellLinks', 'CellUpdate', + 'CellWithViewProperties', 'Check', 'CheckBase', 'CheckBaseLinks', 'CheckDiscriminator', 'CheckPatch', + 'CheckStatusLevel', 'CheckViewProperties', 'Checks', 'ColumnDataType', 'ColumnSemanticType', + 'ConditionalExpression', 'Config', 'ConstantVariableProperties', 'CreateCell', 'CreateDashboardRequest', + 'CustomCheck', 'DBRP', 'DBRPCreate', 'DBRPGet', 'DBRPUpdate', 'DBRPs', 'Dashboard', 'DashboardColor', + 'DashboardQuery', 'DashboardWithViewProperties', 'Dashboards', 'DateTimeLiteral', 'DeadmanCheck', + 'DecimalPlaces', 'DeletePredicateRequest', 'Dialect', 'DictExpression', 'DictItem', 'Duration', + 'DurationLiteral', 'Error', 'Expression', 'ExpressionStatement', 'Field', 'File', 'FloatLiteral', + 'FluxResponse', 'FluxSuggestion', 'FluxSuggestions', 'FunctionExpression', 'GaugeViewProperties', + 'GreaterThreshold', 'HTTPNotificationEndpoint', 'HTTPNotificationRule', 'HTTPNotificationRuleBase', + 'HealthCheck', 'HeatmapViewProperties', 'HistogramViewProperties', 'Identifier', 'ImportDeclaration', + 'IndexExpression', 'IntegerLiteral', 'IsOnboarding', 'Label', 'LabelCreateRequest', 'LabelMapping', + 'LabelResponse', 'LabelUpdate', 'LabelsResponse', 'LanguageRequest', 'LegacyAuthorizationPostRequest', + 'LesserThreshold', 'LinePlusSingleStatProperties', 'LineProtocolError', 'LineProtocolLengthError', 'Links', + 'ListStacksResponse', 'LogEvent', 'LogicalExpression', 'Logs', 'MapVariableProperties', + 'MarkdownViewProperties', 'MeasurementSchema', 'MeasurementSchemaColumn', 'MeasurementSchemaCreateRequest', + 'MeasurementSchemaList', 'MeasurementSchemaUpdateRequest', 'MemberAssignment', 'MemberExpression', + 'MetadataBackup', 'ModelProperty', 'MosaicViewProperties', 'Node', 'NotificationEndpoint', + 'NotificationEndpointBase', 'NotificationEndpointBaseLinks', 'NotificationEndpointDiscriminator', + 'NotificationEndpointType', 'NotificationEndpointUpdate', 'NotificationEndpoints', 'NotificationRule', + 'NotificationRuleBase', 'NotificationRuleBaseLinks', 'NotificationRuleDiscriminator', + 'NotificationRuleUpdate', 'NotificationRules', 'ObjectExpression', 'OnboardingRequest', 'OnboardingResponse', + 'OptionStatement', 'Organization', 'OrganizationLinks', 'Organizations', 'Package', 'PackageClause', + 'PagerDutyNotificationEndpoint', 'PagerDutyNotificationRule', 'PagerDutyNotificationRuleBase', + 'ParenExpression', 'PasswordResetBody', 'PatchBucketRequest', 'PatchDashboardRequest', + 'PatchOrganizationRequest', 'PatchRetentionRule', 'PatchStackRequest', + 'PatchStackRequestAdditionalResources', 'Permission', 'PermissionResource', 'PipeExpression', 'PipeLiteral', + 'PostBucketRequest', 'PostCheck', 'PostNotificationEndpoint', 'PostNotificationRule', + 'PostOrganizationRequest', 'PostRestoreKVResponse', 'PostStackRequest', 'PropertyKey', 'Query', + 'QueryEditMode', 'QueryVariableProperties', 'QueryVariablePropertiesValues', 'RangeThreshold', 'Ready', + 'RegexpLiteral', 'RemoteConnection', 'RemoteConnectionCreationRequest', 'RemoteConnectionUpdateRequest', + 'RemoteConnections', 'RenamableField', 'Replication', 'ReplicationCreationRequest', + 'ReplicationUpdateRequest', 'Replications', 'ResourceMember', 'ResourceMembers', 'ResourceMembersLinks', + 'ResourceOwner', 'ResourceOwners', 'RestoredBucketMappings', 'RetentionPolicyManifest', 'ReturnStatement', + 'Routes', 'RoutesExternal', 'RoutesQuery', 'RoutesSystem', 'RuleStatusLevel', 'Run', 'RunLinks', + 'RunManually', 'Runs', 'SMTPNotificationRule', 'SMTPNotificationRuleBase', 'ScatterViewProperties', + 'SchemaType', 'ScraperTargetRequest', 'ScraperTargetResponse', 'ScraperTargetResponses', 'Script', + 'ScriptCreateRequest', 'ScriptInvocationParams', 'ScriptLanguage', 'ScriptUpdateRequest', 'Scripts', + 'SecretKeys', 'SecretKeysResponse', 'ShardGroupManifest', 'ShardManifest', 'ShardOwner', + 'SimpleTableViewProperties', 'SingleStatViewProperties', 'SlackNotificationEndpoint', + 'SlackNotificationRule', 'SlackNotificationRuleBase', 'Source', 'SourceLinks', 'Sources', 'Stack', + 'StackAssociations', 'StackEvents', 'StackLinks', 'StackResources', 'Statement', 'StaticLegend', + 'StatusRule', 'StringLiteral', 'SubscriptionManifest', 'TableViewProperties', + 'TableViewPropertiesTableOptions', 'TagRule', 'Task', 'TaskCreateRequest', 'TaskLinks', 'TaskStatusType', + 'TaskUpdateRequest', 'Tasks', 'Telegraf', 'TelegrafPlugin', 'TelegrafPluginRequest', + 'TelegrafPluginRequestPlugins', 'TelegrafPlugins', 'TelegrafRequest', 'TelegrafRequestMetadata', 'Telegrafs', + 'TelegramNotificationEndpoint', 'TelegramNotificationRule', 'TelegramNotificationRuleBase', 'TemplateApply', + 'TemplateApplyRemotes', 'TemplateApplyTemplate', 'TemplateChart', 'TemplateExportByID', + 'TemplateExportByIDOrgIDs', 'TemplateExportByIDResourceFilters', 'TemplateExportByIDResources', + 'TemplateKind', 'TemplateSummary', 'TemplateSummaryDiff', 'TemplateSummaryDiffBuckets', + 'TemplateSummaryDiffBucketsNewOld', 'TemplateSummaryDiffChecks', 'TemplateSummaryDiffDashboards', + 'TemplateSummaryDiffDashboardsNewOld', 'TemplateSummaryDiffLabelMappings', 'TemplateSummaryDiffLabels', + 'TemplateSummaryDiffLabelsNewOld', 'TemplateSummaryDiffNotificationEndpoints', + 'TemplateSummaryDiffNotificationRules', 'TemplateSummaryDiffNotificationRulesNewOld', + 'TemplateSummaryDiffTasks', 'TemplateSummaryDiffTasksNewOld', 'TemplateSummaryDiffTelegrafConfigs', + 'TemplateSummaryDiffVariables', 'TemplateSummaryDiffVariablesNewOld', 'TemplateSummaryErrors', + 'TemplateSummaryLabel', 'TemplateSummaryLabelProperties', 'TemplateSummarySummary', + 'TemplateSummarySummaryBuckets', 'TemplateSummarySummaryDashboards', 'TemplateSummarySummaryLabelMappings', + 'TemplateSummarySummaryNotificationRules', 'TemplateSummarySummaryStatusRules', + 'TemplateSummarySummaryTagRules', 'TemplateSummarySummaryTasks', 'TemplateSummarySummaryVariables', + 'TestStatement', 'Threshold', 'ThresholdBase', 'ThresholdCheck', 'UnaryExpression', 'UnsignedIntegerLiteral', + 'User', 'UserResponse', 'UserResponseLinks', 'Users', 'Variable', 'VariableAssignment', 'VariableLinks', + 'VariableProperties', 'Variables', 'View', 'ViewLinks', 'ViewProperties', 'Views', 'WritePrecision', + 'XYGeom', 'XYViewProperties', 'AuthorizationsApi', 'BucketsApi', 'DeleteApi', 'InvokableScriptsApi', + 'LabelsApi', 'OrganizationsApi', 'QueryApi', 'TasksApi', 'UsersApi', 'WriteApi', 'WriteOptions', + 'InfluxDBClient', 'InfluxLoggingHandler', 'Point', 'VERSION'] diff --git a/setup.py b/setup.py index 649a01d6..ce746544 100644 --- a/setup.py +++ b/setup.py @@ -12,6 +12,7 @@ ] test_requires = [ + 'mypy>=0.991', 'flake8>=5.0.3', 'coverage>=4.0.3', 'nose>=1.3.7', diff --git a/tests/test_PublicExports.py b/tests/test_PublicExports.py new file mode 100644 index 00000000..bf97cf29 --- /dev/null +++ b/tests/test_PublicExports.py @@ -0,0 +1,27 @@ +""" +courtesy of ac1982@no-response.github.com + +Exercise top-level imports as both runtime and typed client code. +""" + +import runpy +import subprocess +import sys +import tempfile +import unittest +from pathlib import Path + + +class PublicExportsTest(unittest.TestCase): + def test_public_imports(self): + root = Path(__file__).resolve().parents[1] + fixture = root / "tests" / "typing" / "public_exports.py" + runpy.run_path(str(fixture), run_name="__main__") + with tempfile.TemporaryDirectory() as cache: + result = subprocess.run( + [sys.executable, "-m", "mypy", "--no-implicit-reexport", + "--follow-imports=silent", "--ignore-missing-imports", + "--cache-dir", cache, str(fixture)], + cwd=str(root), capture_output=True, text=True, + ) + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) diff --git a/tests/typing/public_exports.py b/tests/typing/public_exports.py new file mode 100644 index 00000000..7a29522f --- /dev/null +++ b/tests/typing/public_exports.py @@ -0,0 +1,33 @@ +"""Check the public imports of an Python client. + +Courtesy of ac1982@no-response.github.com + +Run with: + python -m mypy --no-implicit-reexport --follow-imports=silent tests/typing/public_exports.py + python tests/typing/public_exports.py +""" + +from influxdb_client import ( + Bucket, + BucketsService, + Configuration, + InfluxDBClient, + Point, + WriteOptions, + WritePrecision, +) + + +def check_exports() -> None: + point = Point("temperature").tag("room", "office").field("value", 21) + assert point.to_line_protocol() == "temperature,room=office value=21i" + assert WriteOptions(batch_size=10).batch_size == 10 + assert WritePrecision.NS == "ns" + assert Bucket is not None + assert BucketsService is not None + assert Configuration is not None + assert InfluxDBClient is not None + + +if __name__ == "__main__": + check_exports()