contextbase-plugin-notion 0.0.0a1__py3-none-any.whl
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.
- contextbase_plugin_notion-0.0.0a1.dist-info/METADATA +9 -0
- contextbase_plugin_notion-0.0.0a1.dist-info/RECORD +8 -0
- contextbase_plugin_notion-0.0.0a1.dist-info/WHEEL +4 -0
- contextbase_plugin_notion-0.0.0a1.dist-info/entry_points.txt +3 -0
- plugin_notion/__init__.py +0 -0
- plugin_notion/binding_config.py +7 -0
- plugin_notion/component.py +133 -0
- plugin_notion/plugin.json +9 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: contextbase-plugin-notion
|
|
3
|
+
Version: 0.0.0a1
|
|
4
|
+
Summary: Notion plugin for ContextBase (PyAirbyte-backed)
|
|
5
|
+
Author: Alizain Feerasta
|
|
6
|
+
Author-email: Alizain Feerasta <alizain.feerasta@gmail.com>
|
|
7
|
+
Requires-Dist: contextbase-shared-plugins==0.0.0a1
|
|
8
|
+
Requires-Dist: dagster==1.12.14
|
|
9
|
+
Requires-Python: >=3.12, <3.13
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
plugin_notion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
plugin_notion/binding_config.py,sha256=x2eHUTfvhvOZNFiSRZmNXBulmVeqWB5Lumn5YDT796M,213
|
|
3
|
+
plugin_notion/component.py,sha256=9GGrEN0rM4CKZLfHdKfv6ewP1yyP40uMrtjB-_sxcTs,4875
|
|
4
|
+
plugin_notion/plugin.json,sha256=aW2PBpGnxbYALNrTL-_eTTHxxrnadj_FtRMBtgCPKeM,123
|
|
5
|
+
contextbase_plugin_notion-0.0.0a1.dist-info/WHEEL,sha256=i9aSRDivn5iP9LaR1BLQX2GNAuriQWPsFwbbWygTX2k,81
|
|
6
|
+
contextbase_plugin_notion-0.0.0a1.dist-info/entry_points.txt,sha256=MBxyUvEswoF3tec4R9bKwmhhdfrrBYgZgBWYY-rzCeo,77
|
|
7
|
+
contextbase_plugin_notion-0.0.0a1.dist-info/METADATA,sha256=rNkxpIJLv4QtrwN0sF38S9TFATxKYdMq0Yi699uzbBs,328
|
|
8
|
+
contextbase_plugin_notion-0.0.0a1.dist-info/RECORD,,
|
|
File without changes
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import dagster as dg
|
|
2
|
+
from dagster import AssetExecutionContext
|
|
3
|
+
from shared_plugins.automation import non_overlapping_automation_condition
|
|
4
|
+
from shared_plugins.bindings import (
|
|
5
|
+
parse_binding_config,
|
|
6
|
+
require_authenticated_account,
|
|
7
|
+
)
|
|
8
|
+
from shared_plugins.base_platform import BasePlatformClient
|
|
9
|
+
from shared_plugins.dlt import resolve_partition_binding
|
|
10
|
+
from shared_plugins.naming import (
|
|
11
|
+
dagster_airbyte_sync_asset_key,
|
|
12
|
+
dagster_asset_group_name,
|
|
13
|
+
dagster_asset_tags,
|
|
14
|
+
dagster_partition_def_name,
|
|
15
|
+
dagster_pool_name,
|
|
16
|
+
plugin_id_from_module,
|
|
17
|
+
)
|
|
18
|
+
from shared_plugins.provider_token import ProviderTokenClient, ProviderTokenLease
|
|
19
|
+
from shared_plugins.pyairbyte import (
|
|
20
|
+
build_pyairbyte_source,
|
|
21
|
+
require_pyairbyte_selected_stream_names,
|
|
22
|
+
run_pyairbyte_sync,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
from .binding_config import NotionBindingConfig
|
|
26
|
+
|
|
27
|
+
PLUGIN_ID = plugin_id_from_module(__file__)
|
|
28
|
+
DOCKER_IMAGE = "airbyte/source-notion:4.0.5"
|
|
29
|
+
|
|
30
|
+
# Every stream source-notion 4.0.5 exposes (exact manifest stream names — 4.x
|
|
31
|
+
# renamed databases to data_sources). A binding with no models.active syncs all
|
|
32
|
+
# of them; models.active narrows.
|
|
33
|
+
ALL_STREAM_NAMES = (
|
|
34
|
+
"pages",
|
|
35
|
+
"users",
|
|
36
|
+
"data_sources",
|
|
37
|
+
"comments",
|
|
38
|
+
"blocks",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
SOURCE_UPDATED_AT_FIELDS = {
|
|
42
|
+
"pages": "last_edited_time",
|
|
43
|
+
"data_sources": "last_edited_time",
|
|
44
|
+
"blocks": "last_edited_time",
|
|
45
|
+
"comments": "last_edited_time",
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _build_connector_config(
|
|
50
|
+
cfg: NotionBindingConfig,
|
|
51
|
+
lease: ProviderTokenLease,
|
|
52
|
+
) -> dict[str, object]:
|
|
53
|
+
return {
|
|
54
|
+
**cfg.model_dump(mode="json", exclude_none=True),
|
|
55
|
+
# The OAuth-minted token rides the plain token credentials shape — at
|
|
56
|
+
# sync time both shapes are the same bearer; the OAuth2.0 variant's
|
|
57
|
+
# client_id/client_secret only serve Airbyte Cloud's managed refresh,
|
|
58
|
+
# which the provider-token redemption replaces.
|
|
59
|
+
"credentials": {
|
|
60
|
+
"auth_type": "token",
|
|
61
|
+
"token": lease.access_token,
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class NotionSyncComponent(dg.Component):
|
|
67
|
+
def build_defs(self, context: dg.ComponentLoadContext) -> dg.Definitions:
|
|
68
|
+
partitions_def = dg.DynamicPartitionsDefinition(
|
|
69
|
+
name=dagster_partition_def_name(PLUGIN_ID)
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
@dg.asset(
|
|
73
|
+
key=dagster_airbyte_sync_asset_key(PLUGIN_ID),
|
|
74
|
+
group_name=dagster_asset_group_name(PLUGIN_ID),
|
|
75
|
+
tags=dagster_asset_tags(PLUGIN_ID, extra_tags={"ctx_primary": "true"}),
|
|
76
|
+
automation_condition=non_overlapping_automation_condition(
|
|
77
|
+
dg.AutomationCondition.on_missing()
|
|
78
|
+
| dg.AutomationCondition.on_cron("*/15 * * * *")
|
|
79
|
+
),
|
|
80
|
+
partitions_def=partitions_def,
|
|
81
|
+
pool=dagster_pool_name(PLUGIN_ID),
|
|
82
|
+
)
|
|
83
|
+
def notion_sync_asset(
|
|
84
|
+
context: AssetExecutionContext,
|
|
85
|
+
base_platform: dg.ResourceParam[BasePlatformClient],
|
|
86
|
+
provider_token: dg.ResourceParam[ProviderTokenClient],
|
|
87
|
+
):
|
|
88
|
+
binding = resolve_partition_binding(
|
|
89
|
+
context=context,
|
|
90
|
+
base_platform=base_platform,
|
|
91
|
+
plugin_id=PLUGIN_ID,
|
|
92
|
+
)
|
|
93
|
+
binding_id = binding.binding_id
|
|
94
|
+
cfg = parse_binding_config(binding, NotionBindingConfig)
|
|
95
|
+
auth = require_authenticated_account(binding)
|
|
96
|
+
# PyAirbyte consumes the token synchronously within one sync, and
|
|
97
|
+
# notion leases declare no expiry (long-lived token, null
|
|
98
|
+
# accessTokenExpiresAt) — so redeem once with no refresh handler.
|
|
99
|
+
# Recovery from a revoked token is a refresh=True redemption.
|
|
100
|
+
lease = provider_token.redeem(
|
|
101
|
+
provider_id=auth.provider_id,
|
|
102
|
+
account_id=auth.account_id,
|
|
103
|
+
)
|
|
104
|
+
selected_stream_names = require_pyairbyte_selected_stream_names(
|
|
105
|
+
binding, default_active=ALL_STREAM_NAMES
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
connector_config = _build_connector_config(cfg, lease)
|
|
109
|
+
source = build_pyairbyte_source(
|
|
110
|
+
docker_image=DOCKER_IMAGE,
|
|
111
|
+
connector_config=connector_config,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
return run_pyairbyte_sync(
|
|
115
|
+
context=context,
|
|
116
|
+
plugin_id=PLUGIN_ID,
|
|
117
|
+
binding_id=binding_id,
|
|
118
|
+
selected_stream_names=selected_stream_names,
|
|
119
|
+
source_updated_at_fields=SOURCE_UPDATED_AT_FIELDS,
|
|
120
|
+
source=source,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
automation_sensor = dg.AutomationConditionSensorDefinition(
|
|
124
|
+
name="notion_automation_sensor",
|
|
125
|
+
target=dg.AssetSelection.assets(notion_sync_asset),
|
|
126
|
+
default_status=dg.DefaultSensorStatus.RUNNING,
|
|
127
|
+
minimum_interval_seconds=30,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
return dg.Definitions(
|
|
131
|
+
assets=[notion_sync_asset],
|
|
132
|
+
sensors=[automation_sensor],
|
|
133
|
+
)
|