snowflake-connector-python 3.16.0__cp313-cp313-win_amd64.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 (246) hide show
  1. snowflake/connector/__init__.py +96 -0
  2. snowflake/connector/_query_context_cache.py +276 -0
  3. snowflake/connector/_sql_util.py +48 -0
  4. snowflake/connector/_utils.py +70 -0
  5. snowflake/connector/arrow_context.py +203 -0
  6. snowflake/connector/auth/__init__.py +53 -0
  7. snowflake/connector/auth/_auth.py +586 -0
  8. snowflake/connector/auth/_http_server.py +220 -0
  9. snowflake/connector/auth/_oauth_base.py +400 -0
  10. snowflake/connector/auth/by_plugin.py +219 -0
  11. snowflake/connector/auth/default.py +36 -0
  12. snowflake/connector/auth/idtoken.py +72 -0
  13. snowflake/connector/auth/keypair.py +222 -0
  14. snowflake/connector/auth/no_auth.py +39 -0
  15. snowflake/connector/auth/oauth.py +49 -0
  16. snowflake/connector/auth/oauth_code.py +479 -0
  17. snowflake/connector/auth/oauth_credentials.py +66 -0
  18. snowflake/connector/auth/okta.py +335 -0
  19. snowflake/connector/auth/pat.py +39 -0
  20. snowflake/connector/auth/usrpwdmfa.py +69 -0
  21. snowflake/connector/auth/webbrowser.py +502 -0
  22. snowflake/connector/auth/workload_identity.py +94 -0
  23. snowflake/connector/azure_storage_client.py +276 -0
  24. snowflake/connector/backoff_policies.py +141 -0
  25. snowflake/connector/bind_upload_agent.py +89 -0
  26. snowflake/connector/cache.py +696 -0
  27. snowflake/connector/compat.py +127 -0
  28. snowflake/connector/config_manager.py +496 -0
  29. snowflake/connector/connection.py +2273 -0
  30. snowflake/connector/connection_diagnostic.py +776 -0
  31. snowflake/connector/constants.py +442 -0
  32. snowflake/connector/converter.py +785 -0
  33. snowflake/connector/converter_issue23517.py +87 -0
  34. snowflake/connector/converter_null.py +14 -0
  35. snowflake/connector/converter_snowsql.py +205 -0
  36. snowflake/connector/cursor.py +1951 -0
  37. snowflake/connector/dbapi.py +53 -0
  38. snowflake/connector/description.py +19 -0
  39. snowflake/connector/direct_file_operation_utils.py +88 -0
  40. snowflake/connector/encryption_util.py +220 -0
  41. snowflake/connector/errorcode.py +91 -0
  42. snowflake/connector/errors.py +615 -0
  43. snowflake/connector/externals_utils/__init__.py +0 -0
  44. snowflake/connector/externals_utils/externals_setup.py +27 -0
  45. snowflake/connector/feature.py +4 -0
  46. snowflake/connector/file_compression_type.py +118 -0
  47. snowflake/connector/file_lock.py +72 -0
  48. snowflake/connector/file_transfer_agent.py +1215 -0
  49. snowflake/connector/file_util.py +153 -0
  50. snowflake/connector/gcs_storage_client.py +474 -0
  51. snowflake/connector/gzip_decoder.py +85 -0
  52. snowflake/connector/local_storage_client.py +90 -0
  53. snowflake/connector/log_configuration.py +60 -0
  54. snowflake/connector/logging_utils/__init__.py +0 -0
  55. snowflake/connector/logging_utils/filters.py +72 -0
  56. snowflake/connector/nanoarrow_arrow_iterator.cp313-win_amd64.pyd +0 -0
  57. snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.cpp +60 -0
  58. snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.hpp +29 -0
  59. snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.cpp +19 -0
  60. snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.hpp +26 -0
  61. snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.cpp +21 -0
  62. snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.hpp +23 -0
  63. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.cpp +557 -0
  64. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.hpp +98 -0
  65. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.cpp +125 -0
  66. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.hpp +115 -0
  67. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.cpp +1005 -0
  68. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.hpp +127 -0
  69. snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.cpp +47 -0
  70. snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.hpp +46 -0
  71. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.cpp +83 -0
  72. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.hpp +35 -0
  73. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.cpp +97 -0
  74. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.hpp +72 -0
  75. snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.cpp +73 -0
  76. snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.hpp +28 -0
  77. snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.cpp +30 -0
  78. snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.hpp +35 -0
  79. snowflake/connector/nanoarrow_cpp/ArrowIterator/IColumnConverter.hpp +17 -0
  80. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.cpp +23 -0
  81. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.hpp +45 -0
  82. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.cpp +71 -0
  83. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.hpp +56 -0
  84. snowflake/connector/nanoarrow_cpp/ArrowIterator/LICENSE.txt +209 -0
  85. snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.cpp +75 -0
  86. snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.hpp +30 -0
  87. snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.cpp +46 -0
  88. snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.hpp +29 -0
  89. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.cpp +8 -0
  90. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.hpp +95 -0
  91. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.cpp +57 -0
  92. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.hpp +36 -0
  93. snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.cpp +34 -0
  94. snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.hpp +48 -0
  95. snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.cpp +19 -0
  96. snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.hpp +26 -0
  97. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.cpp +36 -0
  98. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.hpp +31 -0
  99. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.cpp +346 -0
  100. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.hpp +145 -0
  101. snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/macros.hpp +14 -0
  102. snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.cpp +65 -0
  103. snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.hpp +68 -0
  104. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_accessors.h +101 -0
  105. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_alloc.h +127 -0
  106. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_assert.h +45 -0
  107. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_builder.h +1908 -0
  108. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_emitter.h +215 -0
  109. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_endian.h +125 -0
  110. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_epilogue.h +7 -0
  111. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_flatbuffers.h +55 -0
  112. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_identifier.h +148 -0
  113. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_iov.h +31 -0
  114. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_prologue.h +8 -0
  115. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_refmap.h +144 -0
  116. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_rtconfig.h +162 -0
  117. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_types.h +97 -0
  118. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_verifier.h +239 -0
  119. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/flatcc_portable.h +14 -0
  120. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/paligned_alloc.h +210 -0
  121. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pattributes.h +84 -0
  122. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic.h +84 -0
  123. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_pop.h +20 -0
  124. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_push.h +51 -0
  125. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian.h +206 -0
  126. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian_detect.h +118 -0
  127. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinline.h +19 -0
  128. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinttypes.h +52 -0
  129. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable.h +2 -0
  130. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable_basic.h +25 -0
  131. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstatic_assert.h +67 -0
  132. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdalign.h +162 -0
  133. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdint.h +898 -0
  134. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/punaligned.h +190 -0
  135. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pversion.h +6 -0
  136. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pwarnings.h +52 -0
  137. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc.c +3204 -0
  138. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.c +3217 -0
  139. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.h +3618 -0
  140. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.hpp +379 -0
  141. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_arrow_iterator.pyx +256 -0
  142. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.c +512 -0
  143. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.h +350 -0
  144. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.c +33273 -0
  145. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.h +397 -0
  146. snowflake/connector/nanoarrow_cpp/Logging/logging.cpp +100 -0
  147. snowflake/connector/nanoarrow_cpp/Logging/logging.hpp +49 -0
  148. snowflake/connector/network.py +1297 -0
  149. snowflake/connector/ocsp_asn1crypto.py +447 -0
  150. snowflake/connector/ocsp_snowflake.py +1883 -0
  151. snowflake/connector/options.py +131 -0
  152. snowflake/connector/pandas_tools.py +732 -0
  153. snowflake/connector/proxy.py +43 -0
  154. snowflake/connector/py.typed +0 -0
  155. snowflake/connector/result_batch.py +786 -0
  156. snowflake/connector/result_set.py +319 -0
  157. snowflake/connector/s3_storage_client.py +605 -0
  158. snowflake/connector/secret_detector.py +181 -0
  159. snowflake/connector/sf_dirs.py +64 -0
  160. snowflake/connector/sfbinaryformat.py +35 -0
  161. snowflake/connector/sfdatetime.py +345 -0
  162. snowflake/connector/snow_logging.py +144 -0
  163. snowflake/connector/sqlstate.py +9 -0
  164. snowflake/connector/ssd_internal_keys.py +30 -0
  165. snowflake/connector/ssl_wrap_socket.py +134 -0
  166. snowflake/connector/storage_client.py +478 -0
  167. snowflake/connector/telemetry.py +249 -0
  168. snowflake/connector/telemetry_oob.py +543 -0
  169. snowflake/connector/test_util.py +30 -0
  170. snowflake/connector/time_util.py +159 -0
  171. snowflake/connector/token_cache.py +402 -0
  172. snowflake/connector/tool/__init__.py +0 -0
  173. snowflake/connector/tool/dump_certs.py +57 -0
  174. snowflake/connector/tool/dump_ocsp_response.py +139 -0
  175. snowflake/connector/tool/dump_ocsp_response_cache.py +194 -0
  176. snowflake/connector/tool/probe_connection.py +69 -0
  177. snowflake/connector/url_util.py +49 -0
  178. snowflake/connector/util_text.py +301 -0
  179. snowflake/connector/vendored/__init__.py +3 -0
  180. snowflake/connector/vendored/requests/LICENSE +175 -0
  181. snowflake/connector/vendored/requests/__init__.py +169 -0
  182. snowflake/connector/vendored/requests/__version__.py +14 -0
  183. snowflake/connector/vendored/requests/_internal_utils.py +50 -0
  184. snowflake/connector/vendored/requests/adapters.py +537 -0
  185. snowflake/connector/vendored/requests/api.py +157 -0
  186. snowflake/connector/vendored/requests/auth.py +315 -0
  187. snowflake/connector/vendored/requests/certs.py +17 -0
  188. snowflake/connector/vendored/requests/compat.py +79 -0
  189. snowflake/connector/vendored/requests/cookies.py +561 -0
  190. snowflake/connector/vendored/requests/exceptions.py +140 -0
  191. snowflake/connector/vendored/requests/help.py +134 -0
  192. snowflake/connector/vendored/requests/hooks.py +33 -0
  193. snowflake/connector/vendored/requests/models.py +1033 -0
  194. snowflake/connector/vendored/requests/sessions.py +833 -0
  195. snowflake/connector/vendored/requests/status_codes.py +128 -0
  196. snowflake/connector/vendored/requests/structures.py +99 -0
  197. snowflake/connector/vendored/requests/utils.py +1093 -0
  198. snowflake/connector/vendored/urllib3/LICENSE.txt +21 -0
  199. snowflake/connector/vendored/urllib3/__init__.py +85 -0
  200. snowflake/connector/vendored/urllib3/_collections.py +355 -0
  201. snowflake/connector/vendored/urllib3/_version.py +2 -0
  202. snowflake/connector/vendored/urllib3/connection.py +572 -0
  203. snowflake/connector/vendored/urllib3/connectionpool.py +1137 -0
  204. snowflake/connector/vendored/urllib3/contrib/__init__.py +0 -0
  205. snowflake/connector/vendored/urllib3/contrib/_appengine_environ.py +36 -0
  206. snowflake/connector/vendored/urllib3/contrib/_securetransport/__init__.py +0 -0
  207. snowflake/connector/vendored/urllib3/contrib/_securetransport/bindings.py +519 -0
  208. snowflake/connector/vendored/urllib3/contrib/_securetransport/low_level.py +397 -0
  209. snowflake/connector/vendored/urllib3/contrib/appengine.py +314 -0
  210. snowflake/connector/vendored/urllib3/contrib/ntlmpool.py +130 -0
  211. snowflake/connector/vendored/urllib3/contrib/pyopenssl.py +509 -0
  212. snowflake/connector/vendored/urllib3/contrib/securetransport.py +920 -0
  213. snowflake/connector/vendored/urllib3/contrib/socks.py +216 -0
  214. snowflake/connector/vendored/urllib3/exceptions.py +323 -0
  215. snowflake/connector/vendored/urllib3/fields.py +274 -0
  216. snowflake/connector/vendored/urllib3/filepost.py +98 -0
  217. snowflake/connector/vendored/urllib3/packages/__init__.py +0 -0
  218. snowflake/connector/vendored/urllib3/packages/backports/__init__.py +0 -0
  219. snowflake/connector/vendored/urllib3/packages/backports/makefile.py +51 -0
  220. snowflake/connector/vendored/urllib3/packages/backports/weakref_finalize.py +155 -0
  221. snowflake/connector/vendored/urllib3/packages/six.py +1076 -0
  222. snowflake/connector/vendored/urllib3/poolmanager.py +540 -0
  223. snowflake/connector/vendored/urllib3/request.py +191 -0
  224. snowflake/connector/vendored/urllib3/response.py +885 -0
  225. snowflake/connector/vendored/urllib3/util/__init__.py +49 -0
  226. snowflake/connector/vendored/urllib3/util/connection.py +156 -0
  227. snowflake/connector/vendored/urllib3/util/proxy.py +57 -0
  228. snowflake/connector/vendored/urllib3/util/queue.py +22 -0
  229. snowflake/connector/vendored/urllib3/util/request.py +146 -0
  230. snowflake/connector/vendored/urllib3/util/response.py +107 -0
  231. snowflake/connector/vendored/urllib3/util/retry.py +620 -0
  232. snowflake/connector/vendored/urllib3/util/ssl_.py +495 -0
  233. snowflake/connector/vendored/urllib3/util/ssl_match_hostname.py +159 -0
  234. snowflake/connector/vendored/urllib3/util/ssltransport.py +221 -0
  235. snowflake/connector/vendored/urllib3/util/timeout.py +271 -0
  236. snowflake/connector/vendored/urllib3/util/url.py +435 -0
  237. snowflake/connector/vendored/urllib3/util/wait.py +152 -0
  238. snowflake/connector/version.py +3 -0
  239. snowflake/connector/wif_util.py +407 -0
  240. snowflake_connector_python-3.16.0.dist-info/METADATA +1475 -0
  241. snowflake_connector_python-3.16.0.dist-info/RECORD +246 -0
  242. snowflake_connector_python-3.16.0.dist-info/WHEEL +5 -0
  243. snowflake_connector_python-3.16.0.dist-info/entry_points.txt +4 -0
  244. snowflake_connector_python-3.16.0.dist-info/licenses/LICENSE.txt +202 -0
  245. snowflake_connector_python-3.16.0.dist-info/licenses/NOTICE +8 -0
  246. snowflake_connector_python-3.16.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env python
2
+ """The secret detector detects sensitive information.
3
+
4
+ It masks secrets that might be leaked from two potential avenues
5
+ 1. Out of Band Telemetry
6
+ 2. Logging
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import logging
11
+ import os
12
+ import re
13
+ from typing import NamedTuple
14
+
15
+ MIN_TOKEN_LEN = os.getenv("MIN_TOKEN_LEN", 32)
16
+ MIN_PWD_LEN = os.getenv("MIN_PWD_LEN", 8)
17
+
18
+
19
+ class MaskedMessageData(NamedTuple):
20
+ is_masked: bool = False
21
+ masked_text: str | None = None
22
+ error_str: str | None = None
23
+
24
+
25
+ class SecretDetector(logging.Formatter):
26
+ AWS_KEY_PATTERN = re.compile(
27
+ r"(aws_key_id|aws_secret_key|access_key_id|secret_access_key)\s*=\s*'([^']+)'",
28
+ flags=re.IGNORECASE,
29
+ )
30
+ AWS_TOKEN_PATTERN = re.compile(
31
+ r'(accessToken|tempToken|keySecret)"\s*:\s*"([a-z0-9/+]{32,}={0,2})"',
32
+ flags=re.IGNORECASE,
33
+ )
34
+ SAS_TOKEN_PATTERN = re.compile(
35
+ r"(sig|signature|AWSAccessKeyId|password|passcode)=(?P<secret>[a-z0-9%/+]{16,})",
36
+ flags=re.IGNORECASE,
37
+ )
38
+ PRIVATE_KEY_PATTERN = re.compile(
39
+ r"-{3,}BEGIN [A-Z ]*PRIVATE KEY-{3,}\n([\s\S]*?)\n-{3,}END [A-Z ]*PRIVATE KEY-{3,}",
40
+ flags=re.MULTILINE | re.IGNORECASE,
41
+ )
42
+ PRIVATE_KEY_DATA_PATTERN = re.compile(
43
+ r'"privateKeyData": "([a-z0-9/+=\\n]{10,})"', flags=re.MULTILINE | re.IGNORECASE
44
+ )
45
+ CONNECTION_TOKEN_PATTERN = re.compile(
46
+ r"(token|assertion content)" r"([\'\"\s:=]+)" r"([a-z0-9=/_\-\+\.]{8,})",
47
+ flags=re.IGNORECASE,
48
+ )
49
+
50
+ PASSWORD_PATTERN = re.compile(
51
+ r"(password"
52
+ r"|pwd)"
53
+ r"([\'\"\s:=]+)"
54
+ r"([a-z0-9!\"#\$%&\\\'\(\)\*\+\,-\./:;<=>\?\@\[\]\^_`\{\|\}~]{1,})",
55
+ flags=re.IGNORECASE,
56
+ )
57
+
58
+ SECRET_STARRED_MASK_STR = "****"
59
+
60
+ @staticmethod
61
+ def mask_connection_token(text: str) -> str:
62
+ return SecretDetector.CONNECTION_TOKEN_PATTERN.sub(
63
+ r"\1\2" + f"{SecretDetector.SECRET_STARRED_MASK_STR}", text
64
+ )
65
+
66
+ @staticmethod
67
+ def mask_password(text: str) -> str:
68
+ return SecretDetector.PASSWORD_PATTERN.sub(
69
+ r"\1\2" + f"{SecretDetector.SECRET_STARRED_MASK_STR}", text
70
+ )
71
+
72
+ @staticmethod
73
+ def mask_aws_keys(text: str) -> str:
74
+ return SecretDetector.AWS_KEY_PATTERN.sub(
75
+ r"\1=" + f"'{SecretDetector.SECRET_STARRED_MASK_STR}'", text
76
+ )
77
+
78
+ @staticmethod
79
+ def mask_sas_tokens(text: str) -> str:
80
+ return SecretDetector.SAS_TOKEN_PATTERN.sub(
81
+ r"\1=" + f"{SecretDetector.SECRET_STARRED_MASK_STR}", text
82
+ )
83
+
84
+ @staticmethod
85
+ def mask_aws_tokens(text: str) -> str:
86
+ return SecretDetector.AWS_TOKEN_PATTERN.sub(r'\1":"XXXX"', text)
87
+
88
+ @staticmethod
89
+ def mask_private_key(text: str) -> str:
90
+ return SecretDetector.PRIVATE_KEY_PATTERN.sub(
91
+ "-----BEGIN PRIVATE KEY-----\\\\nXXXX\\\\n-----END PRIVATE KEY-----", text
92
+ )
93
+
94
+ @staticmethod
95
+ def mask_private_key_data(text: str) -> str:
96
+ return SecretDetector.PRIVATE_KEY_DATA_PATTERN.sub(
97
+ '"privateKeyData": "XXXX"', text
98
+ )
99
+
100
+ @staticmethod
101
+ def mask_secrets(text: str) -> MaskedMessageData:
102
+ """Masks any secrets. This is the method that should be used by outside classes.
103
+
104
+ Args:
105
+ text: A string which may contain a secret.
106
+
107
+ Returns:
108
+ The masked string data in MaskedMessageData.
109
+ """
110
+ if text is None:
111
+ return MaskedMessageData()
112
+
113
+ masked = False
114
+ err_str = None
115
+ try:
116
+ masked_text = SecretDetector.mask_connection_token(
117
+ SecretDetector.mask_password(
118
+ SecretDetector.mask_private_key_data(
119
+ SecretDetector.mask_private_key(
120
+ SecretDetector.mask_aws_tokens(
121
+ SecretDetector.mask_sas_tokens(
122
+ SecretDetector.mask_aws_keys(text)
123
+ )
124
+ )
125
+ )
126
+ )
127
+ )
128
+ )
129
+ if masked_text != text:
130
+ masked = True
131
+ except Exception as ex:
132
+ # We'll assume that the exception was raised during masking
133
+ # to be safe consider that the log has sensitive information
134
+ # and do not raise an exception.
135
+ masked = True
136
+ masked_text = str(ex)
137
+ err_str = str(ex)
138
+
139
+ return MaskedMessageData(masked, masked_text, err_str)
140
+
141
+ @staticmethod
142
+ def create_formatting_error_log(
143
+ original_record: logging.LogRecord, error_message: str
144
+ ) -> str:
145
+ return "{} - {} {} - {} - {} - {}".format(
146
+ original_record.asctime,
147
+ original_record.threadName,
148
+ "secret_detector.py",
149
+ "sanitize_log_str",
150
+ original_record.levelname,
151
+ error_message,
152
+ )
153
+
154
+ def format(self, record: logging.LogRecord) -> str:
155
+ """Wrapper around logging module's formatter.
156
+
157
+ This will ensure that the formatted message is free from sensitive credentials.
158
+
159
+ Args:
160
+ record: The logging record.
161
+
162
+ Returns:
163
+ Formatted desensitized log string.
164
+ """
165
+ try:
166
+ unsanitized_log = super().format(record)
167
+ masked, optional_sanitized_log, err_str = SecretDetector.mask_secrets(
168
+ unsanitized_log
169
+ )
170
+ # Added to comply with type hints (Optional[str] is not accepted for str)
171
+ sanitized_log = optional_sanitized_log or ""
172
+
173
+ if masked and err_str is not None:
174
+ sanitized_log = self.create_formatting_error_log(record, err_str)
175
+
176
+ except Exception as ex:
177
+ sanitized_log = self.create_formatting_error_log(
178
+ record, "EXCEPTION - " + str(ex)
179
+ )
180
+
181
+ return sanitized_log
@@ -0,0 +1,64 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import pathlib
5
+ from functools import cached_property
6
+ from typing import Protocol
7
+
8
+ from platformdirs import PlatformDirs
9
+
10
+
11
+ class PlatformDirsProto(Protocol):
12
+ @property
13
+ def user_config_path(self) -> pathlib.Path: ...
14
+
15
+
16
+ def _resolve_platform_dirs() -> PlatformDirsProto:
17
+ """Decide on what PlatformDirs class to use.
18
+
19
+ In case a folder exists (which can be customized with the environmental
20
+ variable `SNOWFLAKE_HOME`) we use that directory as all platform
21
+ directories. If this folder does not exist we'll fall back to platformdirs
22
+ defaults.
23
+
24
+ This helper function was introduced to make this code testable.
25
+ """
26
+ platformdir_kwargs = {
27
+ "appname": "snowflake",
28
+ "appauthor": False,
29
+ }
30
+ snowflake_home = pathlib.Path(
31
+ os.environ.get("SNOWFLAKE_HOME", "~/.snowflake/"),
32
+ ).expanduser()
33
+ if snowflake_home.exists():
34
+ return SFPlatformDirs(
35
+ str(snowflake_home),
36
+ **platformdir_kwargs,
37
+ )
38
+ else:
39
+ # In case SNOWFLAKE_HOME does not exist we fall back to using
40
+ # platformdirs to determine where system files should be placed. Please
41
+ # see docs for all the directories defined in the module at
42
+ # https://platformdirs.readthedocs.io/
43
+ return PlatformDirs(**platformdir_kwargs)
44
+
45
+
46
+ class SFPlatformDirs:
47
+ """Single folder platformdirs.
48
+
49
+ This class introduces a PlatformDir class where everything is placed into a
50
+ single folder. This is intended for users who prefer portability over all
51
+ else.
52
+ """
53
+
54
+ def __init__(
55
+ self,
56
+ single_dir: str,
57
+ **kwargs,
58
+ ) -> None:
59
+ self.single_dir = pathlib.Path(single_dir)
60
+
61
+ @cached_property
62
+ def user_config_path(self) -> str:
63
+ """data directory tied to to the user"""
64
+ return self.single_dir
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env python
2
+ from __future__ import annotations
3
+
4
+ from base64 import b16decode, b16encode, standard_b64encode
5
+
6
+ from .errors import InternalError
7
+
8
+ # Converts a Snowflake binary value into a "bytes" object.
9
+ binary_to_python = b16decode
10
+
11
+
12
+ def binary_to_snowflake(binary_value) -> bytes | bytearray:
13
+ """Encodes a "bytes" object for passing to Snowflake."""
14
+ result = b16encode(binary_value)
15
+
16
+ if isinstance(binary_value, bytearray):
17
+ return bytearray(result)
18
+ return result
19
+
20
+
21
+ class SnowflakeBinaryFormat:
22
+ """Formats binary values ("bytes" objects) in hex or base64."""
23
+
24
+ def __init__(self, name) -> None:
25
+ name = name.upper()
26
+ if name == "HEX":
27
+ self._encode = b16encode
28
+ elif name == "BASE64":
29
+ self._encode = standard_b64encode
30
+ else:
31
+ raise InternalError(f"Unrecognized binary format {name}")
32
+
33
+ def format(self, binary_value):
34
+ """Formats a "bytes" object, returning a string."""
35
+ return self._encode(binary_value).decode("ascii")
@@ -0,0 +1,345 @@
1
+ #!/usr/bin/env python
2
+ from __future__ import annotations
3
+
4
+ import time
5
+ from collections import namedtuple
6
+ from datetime import date, datetime, timedelta
7
+ from time import struct_time
8
+
9
+ ZERO_TIMEDELTA = timedelta(0)
10
+
11
+ ElementType = {
12
+ "Year2digit_ElementType": ["YY", "%y"],
13
+ "Year_ElementType": ["YYYY", "%Y"],
14
+ "Month_ElementType": ["MM", "%m"],
15
+ "MonthAbbrev_ElementType": ["MON", "%b"],
16
+ "DayOfMonth_ElementType": ["DD", "%d"],
17
+ "DayOfWeekAbbrev_ElementType": ["DY", "%a"],
18
+ "Hour24_ElementType": ["HH24", "%H"],
19
+ "Hour12_ElementType": ["HH12", "%I"],
20
+ "Hour_ElementType": ["HH", "%H"],
21
+ "Ante_Meridiem_ElementType": ["AM", "%p"],
22
+ "Post_Meridiem_ElementType": ["PM", "%p"],
23
+ "Minute_ElementType": ["MI", "%M"],
24
+ "Second_ElementType": ["SS", "%S"],
25
+ "MilliSecond_ElementType": ["FF", ""],
26
+ # special code for parsing fractions
27
+ "TZOffsetHourColonMin_ElementType": ["TZH:TZM", "%z"],
28
+ "TZOffsetHourMin_ElementType": ["TZHTZM", "%z"],
29
+ "TZOffsetHourOnly_ElementType": ["TZH", "%z"],
30
+ "TZAbbr_ElementType": ["TZD", "%Z"],
31
+ }
32
+
33
+
34
+ def sfdatetime_total_seconds_from_timedelta(td: timedelta) -> int:
35
+ return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) // 10**6
36
+
37
+
38
+ SnowflakeDateTime = namedtuple("SnowflakeDateTime", "datetime nanosecond scale")
39
+
40
+
41
+ def _support_negative_year(value: SnowflakeDateTime, year_len: int) -> str:
42
+ # if YYYY/YY is included
43
+ return _build_year_format(value.datetime, year_len)
44
+
45
+
46
+ def _support_negative_year_datetime(value, year_len):
47
+ # if YYYY/YY is included
48
+ return _build_year_format(value, year_len)
49
+
50
+
51
+ def _build_year_format(dt: datetime | struct_time, year_len: int) -> str:
52
+ if hasattr(dt, "year"):
53
+ # datetime
54
+ year_raw_value = dt.year
55
+ else:
56
+ # struct_time
57
+ year_raw_value = dt.tm_year
58
+ return _build_raw_year_format(year_raw_value, year_len)
59
+
60
+
61
+ def _support_negative_year_struct_time(dt: struct_time, year_len: int) -> str:
62
+ # struct_time
63
+ return _build_raw_year_format(dt.tm_year, year_len)
64
+
65
+
66
+ def _build_raw_year_format(year_raw_value: int, year_len: int) -> str:
67
+ sign_char = ""
68
+ if year_raw_value < 0:
69
+ sign_char = "-"
70
+ year_raw_value *= -1
71
+ if year_len == 2:
72
+ year_raw_value %= 100
73
+ fmt = sign_char + "{:0" + str(year_len) + "d}"
74
+ return fmt.format(year_raw_value)
75
+
76
+
77
+ def _support_negative_year_date(value, year_len):
78
+ # if YYYY/YY is included
79
+ return _build_year_format(value, year_len)
80
+
81
+
82
+ def _inject_fraction(value: SnowflakeDateTime | datetime, fraction_len: int) -> str:
83
+ # if FF is included
84
+ nano_str = "{:09d}"
85
+
86
+ if hasattr(value, "microsecond"):
87
+ nano_str = "{:06d}"
88
+ fraction = value.microsecond
89
+ elif hasattr(value, "nanosecond"):
90
+ fraction = value.nanosecond
91
+ else:
92
+ nano_str = "{:01d}"
93
+ fraction = 0 # struct_time. no fraction of second
94
+
95
+ if fraction_len > 0:
96
+ # truncate up to the specified length of FF
97
+ nano_value = nano_str.format(fraction)[:fraction_len]
98
+ else:
99
+ # no length of FF is specified
100
+ nano_value = nano_str.format(fraction)
101
+ if hasattr(value, "scale"):
102
+ # but scale is specified
103
+ nano_value = nano_value[: value.scale]
104
+ return nano_value
105
+
106
+
107
+ def _inject_others(_: SnowflakeDateTime | struct_time, value0: str) -> str:
108
+ return value0
109
+
110
+
111
+ NOT_OTHER_FORMAT = {
112
+ _support_negative_year,
113
+ _support_negative_year_datetime,
114
+ _support_negative_year_struct_time,
115
+ _support_negative_year_date,
116
+ _inject_fraction,
117
+ }
118
+
119
+
120
+ class SnowflakeDateTimeFormat:
121
+ """Snowflake DateTime Formatter."""
122
+
123
+ def __init__(
124
+ self,
125
+ sql_format,
126
+ data_type: str = "TIMESTAMP_NTZ",
127
+ datetime_class=datetime,
128
+ support_negative_year: bool = True,
129
+ inject_fraction: bool = True,
130
+ ) -> None:
131
+ self._sql_format = sql_format
132
+ self._ignore_tz = data_type in ("TIMESTAMP_NTZ", "DATE")
133
+ if datetime_class == datetime:
134
+ self._support_negative_year_method = _support_negative_year_datetime
135
+ elif datetime_class == time.struct_time:
136
+ self._support_negative_year_method = _support_negative_year_struct_time
137
+ elif datetime_class == date:
138
+ self._support_negative_year_method = _support_negative_year_date
139
+ else:
140
+ self._support_negative_year_method = _support_negative_year
141
+
142
+ # format method
143
+ self.format = getattr(self, f"_format_{datetime_class.__name__}")
144
+ self._compile(
145
+ support_negative_year=support_negative_year, inject_fraction=inject_fraction
146
+ )
147
+
148
+ def _pre_format(self, value: SnowflakeDateTime | struct_time) -> str:
149
+ fmt = []
150
+ for e in self._elements:
151
+ f = e[0]
152
+ fmt.append(f(value, e[1]))
153
+ return "".join(fmt)
154
+
155
+ def _format_SnowflakeDateTime(self, value: SnowflakeDateTime) -> str:
156
+ """Formats SnowflakeDateTime object."""
157
+ fmt = self._pre_format(value)
158
+ dt = value.datetime
159
+ if isinstance(dt, time.struct_time):
160
+ return str(time.strftime(fmt, dt))
161
+ if dt.year < 1000:
162
+ # NOTE: still not supported
163
+ return dt.isoformat()
164
+ return dt.strftime(fmt)
165
+
166
+ def _format_datetime(self, value):
167
+ """Formats datetime object."""
168
+ fmt = self._pre_format(value)
169
+ if isinstance(value, time.struct_time):
170
+ return str(time.strftime(fmt, value))
171
+ if value.year < 1000:
172
+ # NOTE: still not supported.
173
+ return value.isoformat()
174
+ return value.strftime(fmt)
175
+
176
+ def _match_token(self, sql_fmt, candidates, ignore: bool = False):
177
+ for c in candidates:
178
+ if sql_fmt.startswith(c[0]):
179
+ if not ignore:
180
+ self._elements.append((_inject_others, c[1]))
181
+ return len(c[0])
182
+ self._add_raw_char(sql_fmt[0])
183
+ return 1
184
+
185
+ def _add_raw_char(self, ch) -> None:
186
+ self._elements.append((_inject_others, "%%" if ch == "%" else ch))
187
+
188
+ def _compile(
189
+ self, support_negative_year: bool = True, inject_fraction: bool = True
190
+ ) -> None:
191
+ self._elements = []
192
+ idx = 0
193
+ u_sql_format = self._sql_format.upper()
194
+
195
+ while idx < len(u_sql_format):
196
+ ch = u_sql_format[idx]
197
+ if ch == "A":
198
+ idx += self._match_token(
199
+ u_sql_format[idx:],
200
+ [
201
+ ElementType["Ante_Meridiem_ElementType"],
202
+ ],
203
+ )
204
+ elif ch == "D":
205
+ idx += self._match_token(
206
+ u_sql_format[idx:],
207
+ [
208
+ ElementType["DayOfMonth_ElementType"],
209
+ ElementType["DayOfWeekAbbrev_ElementType"],
210
+ ],
211
+ )
212
+ elif ch == "H":
213
+ idx += self._match_token(
214
+ u_sql_format[idx:],
215
+ [
216
+ ElementType["Hour24_ElementType"],
217
+ ElementType["Hour12_ElementType"],
218
+ ElementType["Hour_ElementType"],
219
+ ],
220
+ )
221
+ elif ch == "M":
222
+ idx += self._match_token(
223
+ u_sql_format[idx:],
224
+ [
225
+ ElementType["MonthAbbrev_ElementType"],
226
+ ElementType["Month_ElementType"],
227
+ ElementType["Minute_ElementType"],
228
+ ],
229
+ )
230
+ elif ch == "P":
231
+ idx += self._match_token(
232
+ u_sql_format[idx:],
233
+ [
234
+ ElementType["Post_Meridiem_ElementType"],
235
+ ],
236
+ )
237
+ elif ch == "S":
238
+ idx += self._match_token(
239
+ u_sql_format[idx:],
240
+ [
241
+ ElementType["Second_ElementType"],
242
+ ],
243
+ )
244
+ elif ch == "T":
245
+ # ignore TZ format if data type doesn't have TZ.
246
+ idx += self._match_token(
247
+ u_sql_format[idx:],
248
+ [
249
+ ElementType["TZOffsetHourColonMin_ElementType"],
250
+ ElementType["TZOffsetHourMin_ElementType"],
251
+ ElementType["TZOffsetHourOnly_ElementType"],
252
+ ElementType["TZAbbr_ElementType"],
253
+ ],
254
+ ignore=self._ignore_tz,
255
+ )
256
+ elif ch == "Y":
257
+ idx += self._match_token(
258
+ u_sql_format[idx:],
259
+ [
260
+ ElementType["Year_ElementType"],
261
+ ElementType["Year2digit_ElementType"],
262
+ ],
263
+ )
264
+ if support_negative_year:
265
+ # Add a special directive to handle YYYY/YY
266
+ last_element = self._elements[-1]
267
+ if last_element[1] == "%Y":
268
+ del self._elements[-1]
269
+ self._elements.append((self._support_negative_year_method, 4))
270
+ elif last_element[1] == "%y":
271
+ del self._elements[-1]
272
+ self._elements.append((self._support_negative_year_method, 2))
273
+
274
+ elif ch == ".":
275
+ if idx + 1 < len(u_sql_format) and u_sql_format[idx + 1 :].startswith(
276
+ ElementType["MilliSecond_ElementType"][0]
277
+ ):
278
+ # Will be FF, just mark that there's a dot before FF
279
+ self._elements.append((_inject_others, "."))
280
+ self._fractions_with_dot = True
281
+ else:
282
+ self._add_raw_char(ch)
283
+ idx += 1
284
+ elif ch == "F":
285
+ if u_sql_format[idx:].startswith(
286
+ ElementType["MilliSecond_ElementType"][0]
287
+ ):
288
+ idx += len(ElementType["MilliSecond_ElementType"][0])
289
+ if inject_fraction:
290
+ # Construct formatter to find fractions position.
291
+ fractions_len = -1
292
+ if idx < len(u_sql_format) and u_sql_format[idx].isdigit():
293
+ # followed by a single digit?
294
+ fractions_len = int(u_sql_format[idx])
295
+ idx += 1
296
+ self._elements.append((_inject_fraction, fractions_len))
297
+ else:
298
+ self._elements.append((_inject_others, "0"))
299
+ else:
300
+ self._add_raw_char(ch)
301
+ idx += 1
302
+ elif ch == '"':
303
+ # copy a double quoted string to the python format
304
+ idx += 1
305
+ start_idx = idx
306
+ while idx < len(self._sql_format) and self._sql_format[idx] != '"':
307
+ idx += 1
308
+
309
+ self._elements.append((_inject_others, self._sql_format[start_idx:idx]))
310
+ if idx < len(self._sql_format):
311
+ idx += 1
312
+ else:
313
+ self._add_raw_char(ch)
314
+ idx += 1
315
+ self._optimize_elements()
316
+
317
+ def _optimize_elements(self) -> None:
318
+ if len(self._elements) < 2:
319
+ return
320
+ last_element = self._elements[-1]
321
+ if last_element[0] in NOT_OTHER_FORMAT:
322
+ return
323
+ second_last_element = self._elements[-2]
324
+ if second_last_element[0] in NOT_OTHER_FORMAT:
325
+ return
326
+ del self._elements[-1]
327
+ del self._elements[-1]
328
+ self._elements.append(
329
+ (_inject_others, second_last_element[1] + last_element[1])
330
+ )
331
+
332
+
333
+ class SnowflakeDateFormat(SnowflakeDateTimeFormat):
334
+ def __init__(self, sql_format, **kwargs) -> None:
335
+ kwargs["inject_fraction"] = False # no fraction
336
+ super().__init__(sql_format, **kwargs)
337
+
338
+ def _format_struct_time(self, value: struct_time) -> str:
339
+ """Formats struct_time."""
340
+ fmt = self._pre_format(value)
341
+ return str(time.strftime(fmt, value))
342
+
343
+ def _format_date(self, value):
344
+ fmt = self._pre_format(value)
345
+ return value.strftime(fmt)