ckanapi-harvesters 0.0.0__py3-none-any.whl → 0.0.3__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.
Files changed (110) hide show
  1. ckanapi_harvesters/__init__.py +32 -10
  2. ckanapi_harvesters/auxiliary/__init__.py +26 -0
  3. ckanapi_harvesters/auxiliary/ckan_action.py +93 -0
  4. ckanapi_harvesters/auxiliary/ckan_api_key.py +213 -0
  5. ckanapi_harvesters/auxiliary/ckan_auxiliary.py +293 -0
  6. ckanapi_harvesters/auxiliary/ckan_configuration.py +50 -0
  7. ckanapi_harvesters/auxiliary/ckan_defs.py +10 -0
  8. ckanapi_harvesters/auxiliary/ckan_errors.py +129 -0
  9. ckanapi_harvesters/auxiliary/ckan_map.py +509 -0
  10. ckanapi_harvesters/auxiliary/ckan_model.py +992 -0
  11. ckanapi_harvesters/auxiliary/ckan_vocabulary_deprecated.py +104 -0
  12. ckanapi_harvesters/auxiliary/deprecated.py +82 -0
  13. ckanapi_harvesters/auxiliary/error_level_message.py +51 -0
  14. ckanapi_harvesters/auxiliary/external_code_import.py +98 -0
  15. ckanapi_harvesters/auxiliary/list_records.py +60 -0
  16. ckanapi_harvesters/auxiliary/login.py +163 -0
  17. ckanapi_harvesters/auxiliary/path.py +208 -0
  18. ckanapi_harvesters/auxiliary/proxy_config.py +298 -0
  19. ckanapi_harvesters/auxiliary/urls.py +40 -0
  20. ckanapi_harvesters/builder/__init__.py +40 -0
  21. ckanapi_harvesters/builder/builder_aux.py +20 -0
  22. ckanapi_harvesters/builder/builder_ckan.py +238 -0
  23. ckanapi_harvesters/builder/builder_errors.py +36 -0
  24. ckanapi_harvesters/builder/builder_field.py +122 -0
  25. ckanapi_harvesters/builder/builder_package.py +9 -0
  26. ckanapi_harvesters/builder/builder_package_1_basic.py +1291 -0
  27. ckanapi_harvesters/builder/builder_package_2_harvesters.py +40 -0
  28. ckanapi_harvesters/builder/builder_package_3_multi_threaded.py +45 -0
  29. ckanapi_harvesters/builder/builder_package_example.xlsx +0 -0
  30. ckanapi_harvesters/builder/builder_resource.py +589 -0
  31. ckanapi_harvesters/builder/builder_resource_datastore.py +561 -0
  32. ckanapi_harvesters/builder/builder_resource_datastore_multi_abc.py +367 -0
  33. ckanapi_harvesters/builder/builder_resource_datastore_multi_folder.py +273 -0
  34. ckanapi_harvesters/builder/builder_resource_datastore_multi_harvester.py +278 -0
  35. ckanapi_harvesters/builder/builder_resource_datastore_unmanaged.py +145 -0
  36. ckanapi_harvesters/builder/builder_resource_datastore_url.py +150 -0
  37. ckanapi_harvesters/builder/builder_resource_init.py +126 -0
  38. ckanapi_harvesters/builder/builder_resource_multi_abc.py +361 -0
  39. ckanapi_harvesters/builder/builder_resource_multi_datastore.py +146 -0
  40. ckanapi_harvesters/builder/builder_resource_multi_file.py +505 -0
  41. ckanapi_harvesters/builder/example/__init__.py +21 -0
  42. ckanapi_harvesters/builder/example/builder_example.py +21 -0
  43. ckanapi_harvesters/builder/example/builder_example_aux_fun.py +24 -0
  44. ckanapi_harvesters/builder/example/builder_example_download.py +44 -0
  45. ckanapi_harvesters/builder/example/builder_example_generate_data.py +73 -0
  46. ckanapi_harvesters/builder/example/builder_example_patch_upload.py +51 -0
  47. ckanapi_harvesters/builder/example/builder_example_policy.py +114 -0
  48. ckanapi_harvesters/builder/example/builder_example_test_sql.py +53 -0
  49. ckanapi_harvesters/builder/example/builder_example_tests.py +87 -0
  50. ckanapi_harvesters/builder/example/builder_example_tests_offline.py +57 -0
  51. ckanapi_harvesters/builder/example/package/ckan-dpg.svg +74 -0
  52. ckanapi_harvesters/builder/example/package/users_local.csv +3 -0
  53. ckanapi_harvesters/builder/mapper_datastore.py +93 -0
  54. ckanapi_harvesters/builder/mapper_datastore_multi.py +262 -0
  55. ckanapi_harvesters/builder/specific/__init__.py +11 -0
  56. ckanapi_harvesters/builder/specific/configuration_builder.py +66 -0
  57. ckanapi_harvesters/builder/specific_builder_abc.py +23 -0
  58. ckanapi_harvesters/ckan_api/__init__.py +20 -0
  59. ckanapi_harvesters/ckan_api/ckan_api.py +11 -0
  60. ckanapi_harvesters/ckan_api/ckan_api_0_base.py +896 -0
  61. ckanapi_harvesters/ckan_api/ckan_api_1_map.py +1028 -0
  62. ckanapi_harvesters/ckan_api/ckan_api_2_readonly.py +934 -0
  63. ckanapi_harvesters/ckan_api/ckan_api_3_policy.py +229 -0
  64. ckanapi_harvesters/ckan_api/ckan_api_4_readwrite.py +579 -0
  65. ckanapi_harvesters/ckan_api/ckan_api_5_manage.py +1225 -0
  66. ckanapi_harvesters/ckan_api/ckan_api_params.py +192 -0
  67. ckanapi_harvesters/ckan_api/deprecated/__init__.py +9 -0
  68. ckanapi_harvesters/ckan_api/deprecated/ckan_api_deprecated.py +267 -0
  69. ckanapi_harvesters/ckan_api/deprecated/ckan_api_deprecated_vocabularies.py +189 -0
  70. ckanapi_harvesters/harvesters/__init__.py +23 -0
  71. ckanapi_harvesters/harvesters/data_cleaner/__init__.py +17 -0
  72. ckanapi_harvesters/harvesters/data_cleaner/data_cleaner_abc.py +240 -0
  73. ckanapi_harvesters/harvesters/data_cleaner/data_cleaner_errors.py +23 -0
  74. ckanapi_harvesters/harvesters/data_cleaner/data_cleaner_upload.py +9 -0
  75. ckanapi_harvesters/harvesters/data_cleaner/data_cleaner_upload_1_basic.py +430 -0
  76. ckanapi_harvesters/harvesters/data_cleaner/data_cleaner_upload_2_geom.py +98 -0
  77. ckanapi_harvesters/harvesters/file_formats/__init__.py +10 -0
  78. ckanapi_harvesters/harvesters/file_formats/csv_format.py +43 -0
  79. ckanapi_harvesters/harvesters/file_formats/file_format_abc.py +39 -0
  80. ckanapi_harvesters/harvesters/file_formats/file_format_init.py +25 -0
  81. ckanapi_harvesters/harvesters/file_formats/shp_format.py +129 -0
  82. ckanapi_harvesters/harvesters/harvester_abc.py +190 -0
  83. ckanapi_harvesters/harvesters/harvester_errors.py +31 -0
  84. ckanapi_harvesters/harvesters/harvester_init.py +30 -0
  85. ckanapi_harvesters/harvesters/harvester_model.py +49 -0
  86. ckanapi_harvesters/harvesters/harvester_params.py +323 -0
  87. ckanapi_harvesters/harvesters/postgre_harvester.py +495 -0
  88. ckanapi_harvesters/harvesters/postgre_params.py +86 -0
  89. ckanapi_harvesters/harvesters/pymongo_data_cleaner.py +173 -0
  90. ckanapi_harvesters/harvesters/pymongo_harvester.py +355 -0
  91. ckanapi_harvesters/harvesters/pymongo_params.py +54 -0
  92. ckanapi_harvesters/policies/__init__.py +20 -0
  93. ckanapi_harvesters/policies/data_format_policy.py +269 -0
  94. ckanapi_harvesters/policies/data_format_policy_abc.py +97 -0
  95. ckanapi_harvesters/policies/data_format_policy_custom_fields.py +156 -0
  96. ckanapi_harvesters/policies/data_format_policy_defs.py +135 -0
  97. ckanapi_harvesters/policies/data_format_policy_errors.py +79 -0
  98. ckanapi_harvesters/policies/data_format_policy_lists.py +234 -0
  99. ckanapi_harvesters/policies/data_format_policy_tag_groups.py +35 -0
  100. ckanapi_harvesters/reports/__init__.py +11 -0
  101. ckanapi_harvesters/reports/admin_report.py +292 -0
  102. {ckanapi_harvesters-0.0.0.dist-info → ckanapi_harvesters-0.0.3.dist-info}/METADATA +84 -38
  103. ckanapi_harvesters-0.0.3.dist-info/RECORD +105 -0
  104. ckanapi_harvesters/divider/__init__.py +0 -27
  105. ckanapi_harvesters/divider/divider.py +0 -53
  106. ckanapi_harvesters/divider/divider_error.py +0 -59
  107. ckanapi_harvesters/main.py +0 -30
  108. ckanapi_harvesters-0.0.0.dist-info/RECORD +0 -9
  109. {ckanapi_harvesters-0.0.0.dist-info → ckanapi_harvesters-0.0.3.dist-info}/WHEEL +0 -0
  110. {ckanapi_harvesters-0.0.0.dist-info → ckanapi_harvesters-0.0.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,238 @@
1
+ #!python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Code to upload metadata to the CKAN server to create/update an existing package
5
+ The metadata is defined by the user in an Excel worksheet
6
+ This file implements the ckan connection definition.
7
+ """
8
+ from typing import Union
9
+ import os
10
+ import json
11
+
12
+ import pandas as pd
13
+
14
+ from ckanapi_harvesters.ckan_api import CkanApi
15
+ from ckanapi_harvesters.auxiliary.ckan_defs import environ_keyword
16
+ from ckanapi_harvesters.auxiliary.path import make_path_relative, path_rel_to_dir
17
+ from ckanapi_harvesters.auxiliary.ckan_auxiliary import _string_from_element
18
+ from ckanapi_harvesters.auxiliary.ckan_auxiliary import ca_file_rel_to_dir, ca_arg_to_str
19
+ from ckanapi_harvesters.auxiliary.proxy_config import ProxyConfig
20
+ from ckanapi_harvesters.policies.data_format_policy import CkanPackageDataFormatPolicy
21
+
22
+
23
+ class BuilderCkan:
24
+ def __init__(self, url:str=None, apikey_file:str=None, proxy:ProxyConfig=None):
25
+ if proxy is None:
26
+ proxy = ProxyConfig()
27
+ self.url: str = url
28
+ self.apikey_file: str = apikey_file
29
+ self._proxy_config: ProxyConfig = proxy
30
+ self._policy_file: Union[str, None] = None
31
+ self._policy: Union[CkanPackageDataFormatPolicy, None] = None
32
+ self.ckan_ca: Union[bool, str, None] = None
33
+ self.extern_ca: Union[bool, str, None] = None
34
+ self._ckan_ca_src: Union[str, None] = None
35
+ self._extern_ca_src: Union[str, None] = None
36
+ self.options_string: Union[str, None] = None
37
+ self.comment: Union[str, None] = None
38
+
39
+ def __str__(self):
40
+ return f"CKAN builder"
41
+
42
+ def __copy__(self):
43
+ return self.copy()
44
+
45
+ def copy(self) -> "BuilderCkan":
46
+ dest = BuilderCkan()
47
+ dest.url = self.url
48
+ dest.apikey_file = self.apikey_file
49
+ dest._proxy_config = self._proxy_config.copy()
50
+ dest._policy_file = self._policy_file
51
+ if self._policy is not None:
52
+ dest._policy = self._policy.copy()
53
+ dest.ckan_ca = self.ckan_ca
54
+ dest.extern_ca = self.extern_ca
55
+ dest._ckan_ca_src = self._ckan_ca_src
56
+ dest._extern_ca_src = self._extern_ca_src
57
+ dest.options_string = self.options_string
58
+ dest.comment = self.comment
59
+ return dest
60
+
61
+ @property
62
+ def proxies(self) -> dict:
63
+ return self._proxy_config.proxies
64
+ @proxies.setter
65
+ def proxies(self, proxies:dict) -> None:
66
+ self._proxy_config.proxies = proxies
67
+ @property
68
+ def proxy_string(self) -> str:
69
+ return self._proxy_config.proxy_string
70
+ @proxy_string.setter
71
+ def proxy_string(self, proxies:str) -> None:
72
+ self._proxy_config.proxy_string = proxies
73
+
74
+ @property
75
+ def policy_file(self) -> str:
76
+ return self._policy_file
77
+ def set_policy_file(self, policy_file:str, *, ckan:CkanApi=None, base_dir:str=None, proxies:dict=None,
78
+ error_not_found:bool=True) -> None:
79
+ if proxies is None:
80
+ proxies = self._proxy_config.proxies
81
+ self._policy_file = policy_file
82
+ if policy_file is not None:
83
+ self._policy = None
84
+ if ckan is None:
85
+ ckan = self.init_ckan(base_dir=base_dir) # initiate a temporary ckan object to enable the load of the default policy
86
+ # self._policy = CkanPackageDataFormatPolicy.from_json(policy_file, base_dir=base_dir, proxies=proxies, error_not_found=error_not_found)
87
+ self._policy = ckan.load_policy(policy_file, base_dir=base_dir, proxies=proxies, error_not_found=error_not_found)
88
+ self._policy_file = self._policy.source_file
89
+ else:
90
+ self._policy = None
91
+ @property
92
+ def policy(self) -> CkanPackageDataFormatPolicy:
93
+ return self._policy
94
+
95
+ def _load_from_df(self, ckan_df: pd.DataFrame, base_dir: str,
96
+ proxies:dict, error_not_found:bool=True) -> None:
97
+ """
98
+ Function to load builder parameters from a DataFrame, usually from an Excel worksheet
99
+
100
+ :param ckan_df:
101
+ :return:
102
+ """
103
+ ckan_df.columns = ckan_df.columns.map(str.lower)
104
+ ckan_df.columns = ckan_df.columns.map(str.strip)
105
+ # order is important here:
106
+ if "ckan url" in ckan_df.columns:
107
+ self.url = _string_from_element(ckan_df.pop("ckan url"))
108
+ if "ckan api key file" in ckan_df.columns:
109
+ self.apikey_file = _string_from_element(ckan_df.pop("ckan api key file"))
110
+ if "proxies" in ckan_df.columns:
111
+ self._proxy_config.proxy_string = _string_from_element(ckan_df.pop("proxies"))
112
+ if "proxy authentication file" in ckan_df.columns:
113
+ proxy_auth_file = _string_from_element(ckan_df.pop("proxy authentication file"))
114
+ if proxy_auth_file is not None:
115
+ self._proxy_config.load_proxy_auth_from_file(proxy_auth_file, base_dir=base_dir)
116
+ self.ckan_ca = None
117
+ self._ckan_ca_src = None
118
+ if "ckan remote ca" in ckan_df.columns:
119
+ ca_cert = _string_from_element(ckan_df.pop("ckan remote ca"))
120
+ self.ckan_ca, self._ckan_ca_src = ca_file_rel_to_dir(ca_cert, base_dir)
121
+ self.extern_ca = None
122
+ self._extern_ca_src = None
123
+ if "external ca" in ckan_df.columns:
124
+ ca_cert = _string_from_element(ckan_df.pop("external ca"))
125
+ self.extern_ca, self._extern_ca_src = ca_file_rel_to_dir(ca_cert, base_dir)
126
+ if "data format policy file" in ckan_df.columns:
127
+ policy_file = _string_from_element(ckan_df.pop("data format policy file"))
128
+ self.set_policy_file(policy_file, base_dir=base_dir, proxies=proxies,
129
+ error_not_found=error_not_found)
130
+ if "options" in ckan_df.columns:
131
+ self.options_string = _string_from_element(ckan_df.pop("options"))
132
+ if "comment" in ckan_df.columns:
133
+ self.comment = _string_from_element(ckan_df.pop("comment"))
134
+
135
+ def _to_dict(self, base_dir:str) -> dict:
136
+ """
137
+ Function to export builder parameters to an Excel worksheet, using the same fields as the input format
138
+
139
+ :see: _load_from_df
140
+ :see: to_xls
141
+ :return:
142
+ """
143
+ ckan_dict = dict()
144
+ ckan_dict["CKAN URL"] = self.url
145
+ ckan_dict["CKAN API key file"] = self.apikey_file
146
+ ckan_dict["Proxies"] = self._proxy_config.proxy_string
147
+ ckan_dict["Proxy authentication file"] = make_path_relative(self._proxy_config.proxy_auth_file, base_dir)
148
+ ckan_dict["CKAN remote CA"] = ca_arg_to_str(self.ckan_ca, base_dir=base_dir, source_string=self._ckan_ca_src)
149
+ ckan_dict["External remote CA"] = ca_arg_to_str(self.extern_ca, base_dir=base_dir, source_string=self._extern_ca_src)
150
+ ckan_dict["Data format policy file"] = make_path_relative(self.policy_file, base_dir)
151
+ ckan_dict["Options"] = self.options_string
152
+ ckan_dict["Comment"] = self.comment
153
+ return ckan_dict
154
+
155
+ def _get_builder_df_help_dict(self) -> dict:
156
+ ckan_help_dict = {
157
+ "CKAN URL": "URL of the CKAN server e.g. https://demo.ckan.org/",
158
+ "CKAN API key file": "Path to a file containing the API key in the first line",
159
+ "Proxies": 'Proxies configuration, either one unique url or {"http": "http://proxy:8082", "https": "http://proxy:8082"}',
160
+ "Proxy authentication file": "Path to a text file containing 3 lines with the proxy authentication method, username and password, relative to this Excel workbook folder. "
161
+ + "This applies to all connexions (to CKAN server and external resources)",
162
+ "CKAN remote CA": "Path to a custom CA certificate for the CKAN server (.pem), relative to this Excel workbook folder",
163
+ "External CA": "Path to a custom CA certificate used for connexions other than the CKAN server, relative to this Excel workbook folder (.pem)",
164
+ "Data format policy file": "Path to a JSON file containing the CKAN data format policy, relative to this Excel workbook folder",
165
+ "Options": "List of options to initialize the CKAN API object in CLI format",
166
+ }
167
+ return ckan_help_dict
168
+
169
+ def _load_from_dict(self, ckan_dict: dict, base_dir: str, proxies:dict=None) -> None:
170
+ ckan_df = pd.DataFrame([ckan_dict], index=["Value"])
171
+ ckan_df = ckan_df.transpose()
172
+ ckan_df.index.name = "Attribute"
173
+ ckan_df = ckan_df.transpose()
174
+ self._load_from_df(ckan_df, base_dir=base_dir, proxies=proxies)
175
+
176
+ def _get_builder_df(self, base_dir:str) -> pd.DataFrame:
177
+ """
178
+ Converts the result of method _to_dict() into a DataFrame
179
+
180
+ :return:
181
+ """
182
+ ckan_dict = self._to_dict(base_dir=base_dir)
183
+ ckan_help_dict = self._get_builder_df_help_dict()
184
+ ckan_df = pd.DataFrame([ckan_dict, ckan_help_dict], index=["Value", "Help"])
185
+ ckan_df = ckan_df.transpose()
186
+ ckan_df.index.name = "Attribute"
187
+ return ckan_df
188
+
189
+ def from_ckan(self, ckan: CkanApi) -> None:
190
+ """
191
+ Initialize fields from a CKAN instance.
192
+ """
193
+ self.url = ckan.url
194
+ self.apikey_file = ckan.apikey.apikey_file
195
+ self._proxy_config = ckan.params._proxy_config
196
+ self.ckan_ca = ckan.params.ckan_ca
197
+ self.extern_ca = ckan.params.extern_ca
198
+ if ckan.policy is not None and ckan.policy_source is not None:
199
+ self.set_policy_file(ckan.policy_source)
200
+
201
+ def init_ckan(self, base_dir:str, ckan:CkanApi=None, default_proxies:dict=None,
202
+ proxies:Union[str,dict,ProxyConfig]=None) -> CkanApi:
203
+ """
204
+ Initialize a CKAN instance, following the parameters of the Excel workbook.
205
+ The parameters from Excel have precedence on the values already contained in the CKAN object.
206
+ However, the Excel workbook might not contain sufficient information.
207
+
208
+ :param base_dir:
209
+ :param ckan:
210
+ :param default_proxies:
211
+ :param proxies:
212
+ :return:
213
+ """
214
+ if ckan is None:
215
+ ckan = CkanApi(url=self.url)
216
+ if self.url is not None:
217
+ ckan.url = self.url.strip()
218
+ if self.apikey_file is not None:
219
+ ckan.load_apikey(self.apikey_file, base_dir=base_dir)
220
+ if self.ckan_ca is not None:
221
+ ckan.ckan_ca = self.ckan_ca
222
+ if self.extern_ca is not None:
223
+ ckan.extern_ca = self.extern_ca
224
+ if proxies is not None:
225
+ # proxies given by argument are prioritary over those specified in the builder
226
+ ckan.set_proxies(proxies)
227
+ elif self._proxy_config.is_defined():
228
+ ckan._proxy_config = self._proxy_config
229
+ ckan._proxy_config.replace_default_proxy(default_proxies)
230
+ elif default_proxies is not None:
231
+ ckan._proxy_config.proxies = default_proxies
232
+ if self.policy is not None:
233
+ ckan.policy = self.policy
234
+ if self.options_string is not None:
235
+ ckan.initialize_from_options_string(self.options_string,
236
+ base_dir=base_dir, default_proxies=default_proxies)
237
+ return ckan
238
+
@@ -0,0 +1,36 @@
1
+ #!python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Data model to represent a CKAN database architecture
5
+ """
6
+ from typing import Iterable
7
+ from ckanapi_harvesters.auxiliary.error_level_message import ContextErrorLevelMessage, ErrorLevel
8
+
9
+ ## Exceptions ------------------
10
+ class EmptyPackageNameException(RuntimeError):
11
+ def __init__(self):
12
+ super().__init__("Run-time error: the attribute package_name cannot be empty")
13
+
14
+ class MissingDataStoreInfoError(Exception):
15
+ def __init__(self):
16
+ super().__init__("DataStore info must be requested to initiate resource builder. Use option datastore_info=True for the map_resources function.")
17
+
18
+ class RequiredDataFrameFieldsError(Exception):
19
+ def __init__(self, missing_fields:Iterable[str]):
20
+ super().__init__("The following fields are required but absent from the sample DataFrame: {}".format(", ".join(missing_fields)))
21
+
22
+ class UnsupportedBuilderVersionError(Exception):
23
+ def __init__(self, file_version):
24
+ super().__init__(f"Version error: package builder version {file_version} is not supported")
25
+
26
+ class MissingCodeFileError(Exception):
27
+ def __init__(self):
28
+ super().__init__("Function names were provided but Auxiliary functions file was not specified")
29
+
30
+ class ResourceFileNotExistMessage(ContextErrorLevelMessage):
31
+ def __init__(self, resource_name:str, error_level:ErrorLevel, specific_message: str):
32
+ super().__init__(f"Resource {resource_name}", error_level, specific_message)
33
+
34
+ class IncompletePatchError(Exception):
35
+ pass
36
+
@@ -0,0 +1,122 @@
1
+ #!python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Code to upload metadata to the CKAN server to create/update an existing package
5
+ The metadata is defined by the user in an Excel worksheet
6
+ This file implements the field definition
7
+ """
8
+ from typing import Union
9
+ import pandas as pd
10
+
11
+ from ckanapi_harvesters.auxiliary.ckan_model import CkanFieldType, CkanField
12
+ from ckanapi_harvesters.auxiliary.ckan_auxiliary import CkanFieldInternalAttrs
13
+ from ckanapi_harvesters.auxiliary.ckan_auxiliary import _string_from_element, _bool_from_string
14
+
15
+
16
+
17
+
18
+ class BuilderField:
19
+ def __init__(self, *, name:str=None, type_override:CkanFieldType=None,
20
+ label:str=None, description:str=None):
21
+ self.name: str = name
22
+ self.type_override: Union[CkanFieldType,None] = type_override
23
+ self.label: Union[str,None] = label
24
+ self.description: Union[str,None] = description
25
+ self.is_index: Union[bool,None] = None
26
+ self.uniquekey: Union[bool,None] = None
27
+ self.notnull: Union[bool,None] = None
28
+ self.options_string: Union[str,None] = None
29
+ self.internal_attrs: CkanFieldInternalAttrs = CkanFieldInternalAttrs()
30
+ self.comment: Union[str,None] = None
31
+
32
+ def __str__(self):
33
+ return f"Field builder for {self.name}"
34
+
35
+ def copy(self, *, dest=None):
36
+ if dest is None:
37
+ dest = BuilderField()
38
+ dest.name = self.name
39
+ dest.type_override = self.type_override
40
+ dest.label = self.label
41
+ dest.description = self.description
42
+ dest.is_index = self.is_index
43
+ dest.uniquekey = self.uniquekey
44
+ dest.notnull = self.notnull
45
+ dest.options_string = self.options_string
46
+ dest.internal_attrs = self.internal_attrs.copy()
47
+ dest.comment = self.comment
48
+ return dest
49
+
50
+ def _load_from_df_row(self, row: pd.Series):
51
+ self.name = _string_from_element(row["field name"]).strip()
52
+ type_override_string = _string_from_element(row["type override"])
53
+ self.type_override = None
54
+ if type_override_string is not None:
55
+ self.type_override = CkanFieldType.from_str(type_override_string)
56
+ else:
57
+ self.type_override = None
58
+ self.label = None
59
+ self.description = None
60
+ if "label" in row.keys():
61
+ self.label = _string_from_element(row["label"])
62
+ if "description" in row.keys():
63
+ self.description = _string_from_element(row["description"])
64
+ if "index" in row.keys():
65
+ self.is_index = _bool_from_string(row["index"], default_value=None)
66
+ if "unique" in row.keys():
67
+ self.uniquekey = _bool_from_string(row["unique"], default_value=None)
68
+ if "not null" in row.keys():
69
+ self.notnull = _bool_from_string(row["not null"], default_value=None)
70
+ if "options" in row.keys():
71
+ self.options_string = _string_from_element(row["options"])
72
+ if "comment" in row.keys():
73
+ self.comment = _string_from_element(row["comment"])
74
+ self.internal_attrs.init_from_native_type(self.type_override)
75
+ self.internal_attrs.init_from_options_string(self.options_string)
76
+
77
+ @staticmethod
78
+ def from_df_row(row: pd.Series) -> "BuilderField":
79
+ field_builder = BuilderField()
80
+ field_builder._load_from_df_row(row)
81
+ return field_builder
82
+
83
+ def _to_dict(self) -> dict:
84
+ return {
85
+ "Field Name": self.name,
86
+ "Type override": str(self.type_override) if self.type_override is not None else "",
87
+ "Label": self.label if self.label else "",
88
+ "Description": self.description if self.description else "",
89
+ "Index": str(self.is_index) if self.is_index is not None else "",
90
+ "Unique": str(self.uniquekey) if self.uniquekey is not None else "",
91
+ "Not null": str(self.notnull) if self.notnull is not None else "",
92
+ "Options": self.options_string if self.options_string else "",
93
+ "Comment": self.comment if self.comment else "",
94
+ }
95
+
96
+ def _to_ckan_field(self) -> CkanField:
97
+ field_info = CkanField(name=self.name, data_type=str(self.type_override) if self.type_override is not None else "",
98
+ notes=self.description, label=self.label)
99
+ field_info.is_index = self.is_index
100
+ field_info.uniquekey = self.uniquekey
101
+ field_info.notnull = self.notnull
102
+ field_info.internal_attrs = self.internal_attrs.copy()
103
+ return field_info
104
+
105
+ def _to_ckan_dict(self) -> dict:
106
+ return self._to_ckan_field().to_ckan_dict()
107
+
108
+ @staticmethod
109
+ def _from_ckan_field(field_info: CkanField) -> "BuilderField":
110
+ field_row = pd.Series({"field name": field_info.name,
111
+ "type override": str(field_info.data_type), # if field_info.type_override else "",
112
+ "label": field_info.label,
113
+ "description": field_info.notes,
114
+ "index": field_info.is_index,
115
+ "unique": field_info.uniquekey,
116
+ "not null": field_info.notnull,
117
+ })
118
+ field_builder = BuilderField()
119
+ field_builder._load_from_df_row(field_row)
120
+ field_builder.internal_attrs = field_info.internal_attrs.copy()
121
+ return field_builder
122
+
@@ -0,0 +1,9 @@
1
+ #!python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Alias to most complete BuilderPackage implementation
5
+ """
6
+
7
+ from ckanapi_harvesters.builder.builder_package_1_basic import example_package_xls
8
+ from ckanapi_harvesters.builder.builder_package_2_harvesters import BuilderPackageWithHarvesters as BuilderPackage # alias
9
+