From f6100627bb326708ddc78e74873caff93fdd37ab Mon Sep 17 00:00:00 2001 From: saurabhsingh2974 Date: Fri, 13 Jun 2025 13:21:21 +0530 Subject: [PATCH 1/6] fixed for snowflake syncer for key-pair authentication The upgrated version of sqlalchemy module now handles p8 files at runtime, eliminating the need to serialize key-pair authentication files. Co-Authored-By: TS-sumeet-jain <168583077+TS-sumeet-jain@users.noreply.github.com> --- cs_tools/sync/snowflake/syncer.py | 42 +++--- pyproject.toml | 4 + uv.lock | 209 ++++++++++++++++++++++++++++-- 3 files changed, 223 insertions(+), 32 deletions(-) diff --git a/cs_tools/sync/snowflake/syncer.py b/cs_tools/sync/snowflake/syncer.py index 183ebc03..f3c4461a 100644 --- a/cs_tools/sync/snowflake/syncer.py +++ b/cs_tools/sync/snowflake/syncer.py @@ -80,25 +80,25 @@ def __repr__(self) -> str: warehouse = self.warehouse return f"" - def _fetch_private_key(self) -> bytes: - """ - Summarized from the Snowflake SQLAlchemy documentation. - - https://github.com/snowflakedb/snowflake-sqlalchemy/tree/main#key-pair-authentication-support - """ - from cryptography.hazmat.backends import default_backend # type: ignore - from cryptography.hazmat.primitives import serialization # type: ignore - - assert self.private_key_path is not None - pem_data = self.private_key_path.read_bytes() - passphrase = self.secret.encode() if self.secret is not None else self.secret - private_key = serialization.load_pem_private_key(data=pem_data, password=passphrase, backend=default_backend()) - pk_as_bytes = private_key.private_bytes( - encoding=serialization.Encoding.DER, - format=serialization.PrivateFormat.PKCS8, - encryption_algorithm=serialization.NoEncryption(), - ) - return pk_as_bytes + # def _fetch_private_key(self) -> bytes: + # """ + # Summarized from the Snowflake SQLAlchemy documentation. + + # https://github.com/snowflakedb/snowflake-sqlalchemy/tree/main#key-pair-authentication-support + # """ + # from cryptography.hazmat.backends import default_backend # type: ignore + # from cryptography.hazmat.primitives import serialization # type: ignore + + # assert self.private_key_path is not None + # pem_data = self.private_key_path.read_bytes() + # passphrase = self.secret.encode() if self.secret is not None else self.secret + # private_key = serialization.load_pem_private_key(data=pem_data,password=passphrase,backend=default_backend()) + # pk_as_bytes = private_key.private_bytes( + # encoding=serialization.Encoding.DER, + # format=serialization.PrivateFormat.PKCS8, + # encryption_algorithm=serialization.NoEncryption(), + # ) + # return pk_as_bytes def make_url(self) -> URL: """Format a connection string for the Snowflake JDBC driver.""" @@ -123,7 +123,9 @@ def make_url(self) -> URL: # SNOWFLAKE DOCS: # https://docs.snowflake.com/en/developer-guide/python-connector/python-connector-connect#using-key-pair-authentication-key-pair-rotation if self.authentication == "key-pair": - url_kwargs["connect_args"]["private_key"] = self._fetch_private_key() + # url_kwargs["connect_args"]["private_key"] = self._fetch_private_key() + url_kwargs["private_key_file"] = self.private_key_path + url_kwargs["private_key_file_pwd"] = self.secret # SNOWFLAKE DOCS: # https://docs.snowflake.com/en/user-guide/admin-security-fed-auth-use#browser-based-sso diff --git a/pyproject.toml b/pyproject.toml index 9f667e54..867dbb7f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,6 +56,10 @@ dependencies = [ "exceptiongroup; python_version < '3.11.0'", "strenum; python_version < '3.11.0'", "taskgroup; python_version < '3.11.0'", + "typer>=0.12.0", + "prompt-toolkit>=3.0.47", + "textual-serve>=1.1.1", + "snowflake-sqlalchemy>=1.7.4", ] [project.urls] diff --git a/uv.lock b/uv.lock index 95ae6e4b..0c336290 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,9 @@ version = 1 requires-python = ">=3.9.2" +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version < '3.10'", +] [[package]] name = "aiohappyeyeballs" @@ -169,6 +173,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/46/eb/e7f063ad1fec6b3178a3cd82d1a3c4de82cccf283fc42746168188e1cdd5/anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a", size = 96041 }, ] +[[package]] +name = "asn1crypto" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/de/cf/d547feed25b5244fcb9392e288ff9fdc3280b10260362fc45d37a798a6ee/asn1crypto-1.5.1.tar.gz", hash = "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c", size = 121080 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/7f/09065fd9e27da0eda08b4d6897f1c13535066174cc023af248fc2a8d5e5a/asn1crypto-1.5.1-py2.py3-none-any.whl", hash = "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67", size = 105045 }, +] + [[package]] name = "async-timeout" version = "5.0.1" @@ -272,6 +285,34 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646 }, ] +[[package]] +name = "boto3" +version = "1.38.36" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, + { name = "jmespath" }, + { name = "s3transfer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c4/22/df130d30dcc73b726c3d254ed855806853b86b987052517337587085b6db/boto3-1.38.36.tar.gz", hash = "sha256:efe0aaa060f8fedd76e5c942055f051aee0432fc722d79d8830a9fd9db83593e", size = 111823 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/ce/f609adc7dfd53792a9b704aa1241f8e5f34c21a5364f64b114d7874f8327/boto3-1.38.36-py3-none-any.whl", hash = "sha256:34c27d7317cadb62c0e9856e5d5aa0271ef47202d340584831048bc7ac904136", size = 139938 }, +] + +[[package]] +name = "botocore" +version = "1.38.36" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jmespath" }, + { name = "python-dateutil" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2e/15/d218917f2d568f6fa92ad3831b31ecc4ee514d775a142385aa87c672bc08/botocore-1.38.36.tar.gz", hash = "sha256:4a1ced1a4218bdff0ed5b46abb54570d473154ddefafa5d121a8d96e4b76ebc1", size = 13966245 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/2d/3ccc58837b3ed8322a15b9fd94114a326e6ab29d36a37508aadf9cf7808e/botocore-1.38.36-py3-none-any.whl", hash = "sha256:b6a50b853f6d23af9edfed89a59800c6bc1687a947cdd3492879f7d64e002d30", size = 13623866 }, +] + [[package]] name = "certifi" version = "2025.1.31" @@ -435,14 +476,14 @@ wheels = [ [[package]] name = "click" -version = "8.1.8" +version = "8.1.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } +sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, + { url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 }, ] [[package]] @@ -532,6 +573,7 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/91/4c/45dfa6829acffa344e3967d6006ee4ae8be57af746ae2eba1c431949b32c/cryptography-44.0.0.tar.gz", hash = "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02", size = 710657 } wheels = [ + { url = "https://files.pythonhosted.org/packages/55/09/8cc67f9b84730ad330b3b72cf867150744bf07ff113cda21a15a1c6d2c7c/cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123", size = 6541833 }, { url = "https://files.pythonhosted.org/packages/7e/5b/3759e30a103144e29632e7cb72aec28cedc79e514b2ea8896bb17163c19b/cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092", size = 3922710 }, { url = "https://files.pythonhosted.org/packages/5f/58/3b14bf39f1a0cfd679e753e8647ada56cddbf5acebffe7db90e184c76168/cryptography-44.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f", size = 4137546 }, { url = "https://files.pythonhosted.org/packages/98/65/13d9e76ca19b0ba5603d71ac8424b5694415b348e719db277b5edc985ff5/cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb", size = 3915420 }, @@ -539,6 +581,9 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/75/ea/af65619c800ec0a7e4034207aec543acdf248d9bffba0533342d1bd435e1/cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543", size = 3932569 }, { url = "https://files.pythonhosted.org/packages/c7/af/d1deb0c04d59612e3d5e54203159e284d3e7a6921e565bb0eeb6269bdd8a/cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e", size = 4016721 }, { url = "https://files.pythonhosted.org/packages/bd/69/7ca326c55698d0688db867795134bdfac87136b80ef373aaa42b225d6dd5/cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e", size = 4240915 }, + { url = "https://files.pythonhosted.org/packages/ef/d4/cae11bf68c0f981e0413906c6dd03ae7fa864347ed5fac40021df1ef467c/cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053", size = 2757925 }, + { url = "https://files.pythonhosted.org/packages/64/b1/50d7739254d2002acae64eed4fc43b24ac0cc44bf0a0d388d1ca06ec5bb1/cryptography-44.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd", size = 3202055 }, + { url = "https://files.pythonhosted.org/packages/11/18/61e52a3d28fc1514a43b0ac291177acd1b4de00e9301aaf7ef867076ff8a/cryptography-44.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591", size = 6542801 }, { url = "https://files.pythonhosted.org/packages/1a/07/5f165b6c65696ef75601b781a280fc3b33f1e0cd6aa5a92d9fb96c410e97/cryptography-44.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7", size = 3922613 }, { url = "https://files.pythonhosted.org/packages/28/34/6b3ac1d80fc174812486561cf25194338151780f27e438526f9c64e16869/cryptography-44.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc", size = 4137925 }, { url = "https://files.pythonhosted.org/packages/d0/c7/c656eb08fd22255d21bc3129625ed9cd5ee305f33752ef2278711b3fa98b/cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289", size = 3915417 }, @@ -546,33 +591,42 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a2/cd/2f3c440913d4329ade49b146d74f2e9766422e1732613f57097fea61f344/cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c", size = 3932331 }, { url = "https://files.pythonhosted.org/packages/7f/df/8be88797f0a1cca6e255189a57bb49237402b1880d6e8721690c5603ac23/cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64", size = 4017372 }, { url = "https://files.pythonhosted.org/packages/af/36/5ccc376f025a834e72b8e52e18746b927f34e4520487098e283a719c205e/cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285", size = 4239657 }, + { url = "https://files.pythonhosted.org/packages/46/b0/f4f7d0d0bcfbc8dd6296c1449be326d04217c57afb8b2594f017eed95533/cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417", size = 2758672 }, + { url = "https://files.pythonhosted.org/packages/97/9b/443270b9210f13f6ef240eff73fd32e02d381e7103969dc66ce8e89ee901/cryptography-44.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede", size = 3202071 }, + { url = "https://files.pythonhosted.org/packages/77/d4/fea74422326388bbac0c37b7489a0fcb1681a698c3b875959430ba550daa/cryptography-44.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731", size = 3338857 }, { url = "https://files.pythonhosted.org/packages/1a/aa/ba8a7467c206cb7b62f09b4168da541b5109838627f582843bbbe0235e8e/cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4", size = 3850615 }, { url = "https://files.pythonhosted.org/packages/89/fa/b160e10a64cc395d090105be14f399b94e617c879efd401188ce0fea39ee/cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756", size = 4081622 }, { url = "https://files.pythonhosted.org/packages/47/8f/20ff0656bb0cf7af26ec1d01f780c5cfbaa7666736063378c5f48558b515/cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c", size = 3867546 }, { url = "https://files.pythonhosted.org/packages/38/d9/28edf32ee2fcdca587146bcde90102a7319b2f2c690edfa627e46d586050/cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa", size = 4090937 }, + { url = "https://files.pythonhosted.org/packages/cc/9d/37e5da7519de7b0b070a3fedd4230fe76d50d2a21403e0f2153d70ac4163/cryptography-44.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c", size = 3128774 }, ] [[package]] name = "cs-tools" -version = "1.6.3" +version = "1.6.4" source = { editable = "." } dependencies = [ { name = "aiosqlite" }, { name = "awesomeversion" }, { name = "betterproto", extra = ["compiler"] }, + { name = "click" }, { name = "email-validator" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "httpx" }, { name = "packaging" }, + { name = "prompt-toolkit" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "rich" }, + { name = "snowflake-sqlalchemy" }, { name = "sqlmodel" }, { name = "strenum", marker = "python_full_version < '3.11'" }, { name = "taskgroup", marker = "python_full_version < '3.11'" }, { name = "tenacity" }, + { name = "textual-serve" }, { name = "thoughtspot-tml" }, { name = "toml" }, + { name = "typer" }, { name = "typing-extensions", marker = "python_full_version < '3.10'" }, { name = "tzdata", marker = "sys_platform == 'win32'" }, ] @@ -616,6 +670,7 @@ requires-dist = [ { name = "aiosqlite" }, { name = "awesomeversion" }, { name = "betterproto", extras = ["compiler"], specifier = "==2.0.0b6" }, + { name = "click", specifier = "==8.1.7" }, { name = "coverage", extras = ["toml"], marker = "extra == 'dev'" }, { name = "email-validator" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, @@ -627,6 +682,7 @@ requires-dist = [ { name = "mypy", marker = "extra == 'dev'" }, { name = "packaging" }, { name = "pre-commit", marker = "extra == 'dev'" }, + { name = "prompt-toolkit", specifier = ">=3.0.47" }, { name = "prompt-toolkit", marker = "extra == 'cli'", specifier = "==3.0.47" }, { name = "prompt-toolkit", marker = "extra == 'dev'", specifier = "==3.0.47" }, { name = "prompt-toolkit", marker = "extra == 'docs'", specifier = "==3.0.47" }, @@ -634,8 +690,9 @@ requires-dist = [ { name = "pydantic-settings" }, { name = "pytest", marker = "extra == 'dev'" }, { name = "python-slugify", extras = ["unidecode"], marker = "extra == 'docs'" }, - { name = "rich", specifier = ">=13.7.1" }, + { name = "rich", specifier = "==13.7.1" }, { name = "ruff", marker = "extra == 'dev'" }, + { name = "snowflake-sqlalchemy", specifier = ">=1.7.4" }, { name = "sqlmodel", specifier = ">=0.0.16" }, { name = "strenum", marker = "python_full_version < '3.11'" }, { name = "taskgroup", marker = "python_full_version < '3.11'" }, @@ -644,11 +701,13 @@ requires-dist = [ { name = "textual", extras = ["syntax"], marker = "extra == 'dev'", specifier = "==1.0.0" }, { name = "textual", extras = ["syntax"], marker = "extra == 'docs'", specifier = "==1.0.0" }, { name = "textual-dev", marker = "extra == 'dev'", specifier = ">=1.7.0" }, + { name = "textual-serve", specifier = ">=1.1.1" }, { name = "textual-serve", marker = "extra == 'cli'", specifier = "==1.1.1" }, { name = "textual-serve", marker = "extra == 'dev'", specifier = "==1.1.1" }, { name = "textual-serve", marker = "extra == 'docs'", specifier = "==1.1.1" }, { name = "thoughtspot-tml" }, { name = "toml" }, + { name = "typer", specifier = ">=0.12.0" }, { name = "typer", marker = "extra == 'cli'", specifier = "==0.12.0" }, { name = "typer", marker = "extra == 'dev'", specifier = "==0.12.0" }, { name = "typer", marker = "extra == 'docs'", specifier = "==0.12.0" }, @@ -1103,6 +1162,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596 }, ] +[[package]] +name = "jmespath" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256 }, +] + [[package]] name = "keyring" version = "25.6.0" @@ -1904,6 +1972,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, ] +[[package]] +name = "pyjwt" +version = "2.10.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997 }, +] + [[package]] name = "pymdown-extensions" version = "10.14.3" @@ -1917,6 +1994,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/eb/f5/b9e2a42aa8f9e34d52d66de87941ecd236570c7ed2e87775ed23bbe4e224/pymdown_extensions-10.14.3-py3-none-any.whl", hash = "sha256:05e0bee73d64b9c71a4ae17c72abc2f700e8bc8403755a00580b49a4e9f189e9", size = 264467 }, ] +[[package]] +name = "pyopenssl" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/8c/cd89ad05804f8e3c17dea8f178c3f40eeab5694c30e0c9f5bcd49f576fc3/pyopenssl-25.1.0.tar.gz", hash = "sha256:8d031884482e0c67ee92bf9a4d8cceb08d92aba7136432ffb0703c5280fc205b", size = 179937 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/80/28/2659c02301b9500751f8d42f9a6632e1508aa5120de5e43042b8b30f8d5d/pyopenssl-25.1.0-py3-none-any.whl", hash = "sha256:2b11f239acc47ac2e5aca04fd7fa829800aeee22a2eb30d744572a157bd8a1ab", size = 56771 }, +] + [[package]] name = "pytest" version = "8.3.4" @@ -1972,6 +2062,15 @@ unidecode = [ { name = "unidecode" }, ] +[[package]] +name = "pytz" +version = "2025.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225 }, +] + [[package]] name = "pywin32-ctypes" version = "0.2.3" @@ -2148,16 +2247,15 @@ wheels = [ [[package]] name = "rich" -version = "13.9.4" +version = "13.7.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } +sdist = { url = "https://files.pythonhosted.org/packages/b3/01/c954e134dc440ab5f96952fe52b4fdc64225530320a910473c1fe270d9aa/rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432", size = 221248 } wheels = [ - { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, + { url = "https://files.pythonhosted.org/packages/87/67/a37f6214d0e9fe57f6ae54b2956d550ca8365857f42a1ce0392bb21d9410/rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222", size = 240681 }, ] [[package]] @@ -2185,6 +2283,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/75/d9/fde7610abd53c0c76b6af72fc679cb377b27c617ba704e25da834e0a0608/ruff-0.9.5-py3-none-win_arm64.whl", hash = "sha256:18a29f1a005bddb229e580795627d297dfa99f16b30c7039e73278cf6b5f9fa9", size = 10064595 }, ] +[[package]] +name = "s3transfer" +version = "0.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ed/5d/9dcc100abc6711e8247af5aa561fc07c4a046f72f659c3adea9a449e191a/s3transfer-0.13.0.tar.gz", hash = "sha256:f5e6db74eb7776a37208001113ea7aa97695368242b364d73e91c981ac522177", size = 150232 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/17/22bf8155aa0ea2305eefa3a6402e040df7ebe512d1310165eda1e233c3f8/s3transfer-0.13.0-py3-none-any.whl", hash = "sha256:0148ef34d6dd964d0d8cf4311b2b21c474693e57c2e069ec708ce043d2b527be", size = 85152 }, +] + [[package]] name = "secretstorage" version = "3.3.3" @@ -2225,6 +2335,81 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] +[[package]] +name = "snowflake-connector-python" +version = "3.15.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asn1crypto" }, + { name = "boto3" }, + { name = "botocore" }, + { name = "certifi" }, + { name = "cffi" }, + { name = "charset-normalizer" }, + { name = "cryptography" }, + { name = "filelock" }, + { name = "idna" }, + { name = "packaging" }, + { name = "platformdirs" }, + { name = "pyjwt" }, + { name = "pyopenssl" }, + { name = "pytz" }, + { name = "requests" }, + { name = "sortedcontainers" }, + { name = "tomlkit" }, + { name = "typing-extensions" }, + { name = "urllib3", marker = "python_full_version < '3.10'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/ff/7c1b2cbb5a43b21abebfa58c83926266e9f5ea05123e795753da6ce84f96/snowflake_connector_python-3.15.0.tar.gz", hash = "sha256:1ef52e2fb3ecc295139737d3d759f85d962ef7278c6990c3bd9c17fcb82508d6", size = 774355 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/eb/9c01764355928258f57663e8f9eacf608b8e03dc093cbcb69244e2ad5de8/snowflake_connector_python-3.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ef92f4ceb61b6a7373ec417f7201d288a6a5a3a42b7e789d3b2221b4dff5ed3c", size = 989157 }, + { url = "https://files.pythonhosted.org/packages/5e/b1/35b31eb3b3303f1d29815a8b28e89d399ea2600933f5a6343943f851c2bd/snowflake_connector_python-3.15.0-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:d33bd2b326d6ea4d49e0cd821f75b3c5f2910be21f4575c1a03d272af78af767", size = 1001262 }, + { url = "https://files.pythonhosted.org/packages/da/e4/7d0a22fd535e15f9625b5726a2a80d53fcb30eb658defff71f93bd536f7c/snowflake_connector_python-3.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56fe48836c5dcda71b951f3f586c036631f7e3d17c3e201489c56974eea5e665", size = 2565688 }, + { url = "https://files.pythonhosted.org/packages/2b/47/1d5bff17d6237f0d0863eae6cfeb85b92a1ec2e95ffae579b0b5b0886e2e/snowflake_connector_python-3.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9345591a62e99f811af6dca758fde873660ced3b4e60a77716f6f2d75b609fd9", size = 2589247 }, + { url = "https://files.pythonhosted.org/packages/79/fe/c0a84498ede55fd48bf21beb855e5a9b0d1cc76b3c8210a989de990b533b/snowflake_connector_python-3.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:21243f2296ceeb238eff871443379665f72125c2086032b40e85ff576df8cc0a", size = 948426 }, + { url = "https://files.pythonhosted.org/packages/af/e6/813f6b299f23f952996da4b4f0f8dade52d5b0f5db516c957b236120cee8/snowflake_connector_python-3.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d6c22820806b43c9f9c5ae3c7758307fb668c42b7ddf74d995b2f0d2da21f08e", size = 989306 }, + { url = "https://files.pythonhosted.org/packages/3e/cf/38dd6ef6bb1a01ab591986b6b903df7f9f4dbb2467b058bebb6ddd4342a3/snowflake_connector_python-3.15.0-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:f83b2e08d29f1bb61c7152bf87f0b8a9e77ee25f09e506f69085a365fe8825df", size = 1001394 }, + { url = "https://files.pythonhosted.org/packages/53/cf/fbf21bc506c032d4a104faf0ced7cbbe6dfecc13e96dd1e211b9c48a08c0/snowflake_connector_python-3.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dbd35265af54ad045cadbed5bfbc76816d2e4d95902f3312365d54c08a33ec3", size = 2590253 }, + { url = "https://files.pythonhosted.org/packages/30/5e/3b325c21e91df06b1868c791f384efd44b142c6d777f9c9322148ccb0a05/snowflake_connector_python-3.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b8757b6206982e784a8f9f24a6fd3de4849e37113788ef677373b6b18907e91", size = 2612009 }, + { url = "https://files.pythonhosted.org/packages/42/d3/9e5125f3a5dac2b8327ad3cb0268842deda8e0b28263320ca752926ce3b2/snowflake_connector_python-3.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:f8994bcfdcd4915b0a365969346939d17ee03e041202048c0d108629bd598d4d", size = 948541 }, + { url = "https://files.pythonhosted.org/packages/bc/be/9b0573ccca48ea97677f326bd367804416691130cd1b9ef84968e8620ae3/snowflake_connector_python-3.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8f41ab707792b07c58214b13e7a6b50d4460f7151e19ea80df3612c92d3a7b76", size = 988559 }, + { url = "https://files.pythonhosted.org/packages/21/d7/6021da04416be8a07a6063038c9d532f583e59cfd14f1bf80bcee34d1f76/snowflake_connector_python-3.15.0-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:d2f0bb00a48c4125090dfe2e8bd15f9389be7867fd9e3c118ecb8dc87c69bcb8", size = 999857 }, + { url = "https://files.pythonhosted.org/packages/1b/de/d4fbd1cfc89e61614ee1963edcd9711369cb6ffea63c4c8d68c3fb248e1a/snowflake_connector_python-3.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:457408eeb4116f73df60bb912fdeb7f6d4849e2cfd7e282b2afb25f080f20188", size = 2602453 }, + { url = "https://files.pythonhosted.org/packages/92/09/6656444e9ff6d83bd1b2c73d1f6b6aab78ff67889e6e3744c8462c74c76f/snowflake_connector_python-3.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63e93f67712260a11ae3bb858c567be805aca5f96d042ff5feacea102a33b49f", size = 2626597 }, + { url = "https://files.pythonhosted.org/packages/c5/04/0b2edacbc7192d8d6a04ca17b81900099c835279157f05c2bac971dc77d2/snowflake_connector_python-3.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:acbceae9120502613991b9997d94cc23ea7e76cdfc3601718025f9f0859cc21e", size = 947264 }, + { url = "https://files.pythonhosted.org/packages/e7/b7/ca38fd1494918e47d23eaa7e3ce883bde5481e7031968894208d5cf726d4/snowflake_connector_python-3.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:52dbe588f7784f194caa739cb394557b81d150f21841d3b51d6d164f1b2e90c0", size = 988902 }, + { url = "https://files.pythonhosted.org/packages/3a/79/22fddcfece8a9813f953b5300e6795ff2cf1744afd0d162001fecffb681a/snowflake_connector_python-3.15.0-cp313-cp313-macosx_11_0_x86_64.whl", hash = "sha256:fcf4090514cc4c8be8f11573b7ed19f6fe6339048271cbdbc18c50a608b57655", size = 1000262 }, + { url = "https://files.pythonhosted.org/packages/9e/bb/7b4d3ea222cbda0f2c2e1825d3599d93512d000bb6c7eecb2a82b6c32511/snowflake_connector_python-3.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64418f6055789a6d1393dfbd3a609e126a88cd015065fad1923ef7b6f4b8dd61", size = 2607481 }, + { url = "https://files.pythonhosted.org/packages/a0/f4/8c820711011b3638c6992609698bcc67dbfb16e93141573e91048f99b505/snowflake_connector_python-3.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9df04e2294605d1e243793b5d889a250d6a301fea8b25c7a84703e3a709a96c", size = 2632032 }, + { url = "https://files.pythonhosted.org/packages/f7/6a/edb52a71b53b9d6d0208ebf47bbe96dab3979da01b6f74eda43232cc1fc2/snowflake_connector_python-3.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ecc5f570000ad957e09517d317ca07645ece77ca9befc88797439164e632738d", size = 989831 }, + { url = "https://files.pythonhosted.org/packages/74/26/dd71a6396b7d606a171433247ae837ae8eb728f4d14971c837f6d3e3a6c0/snowflake_connector_python-3.15.0-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:49e68d5130f17bde2de82bf1c7298803b4ec5bfb926a5daa9001542d710026bc", size = 1001799 }, + { url = "https://files.pythonhosted.org/packages/e2/cb/f965db23e288e8311439adb2b5ee64bc7bb7fa4adcdc34d391ccda92c477/snowflake_connector_python-3.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:698d9dbdd8873daaae01a46ca5d57caf3e4637a30a6afe5ca54cd0c460c359fd", size = 2566380 }, + { url = "https://files.pythonhosted.org/packages/e9/7c/86f80dddf7e895ee4174d0061492b83bfddb346416c071f8d680a147c76f/snowflake_connector_python-3.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04cadd3dae180a5f3632347c2a5836de7ac20fbdf8cb5192e021cad098c85247", size = 2589346 }, + { url = "https://files.pythonhosted.org/packages/82/db/fcd16bb08f478016309a5527f8f03522e2ee1b55a89839ca6b92d6fd9adb/snowflake_connector_python-3.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:0a97deeadfe746fb88475cb83498650e68cf051969476ea498f572e40d49ce96", size = 949123 }, +] + +[[package]] +name = "snowflake-sqlalchemy" +version = "1.7.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "snowflake-connector-python" }, + { name = "sqlalchemy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/68/7181c1cc714335f48f3c2685eed392045e9542aa6b1010462200b9921498/snowflake_sqlalchemy-1.7.4.tar.gz", hash = "sha256:a509ca0f11c5b19a242157189ad20a3ee9598aa391fcbac3ae3e6cf53251a6cb", size = 119579 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/5b/11f75dabb2fd0320ac73409963284723a9b14e3a7a90dbe9a6263ea1f50c/snowflake_sqlalchemy-1.7.4-py3-none-any.whl", hash = "sha256:52e14adf13640ff5543c32a4f0600fdb1e49c5862413ba5e27b08693c8676f82", size = 70507 }, +] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, +] + [[package]] name = "sqlalchemy" version = "2.0.38" @@ -2845,11 +3030,11 @@ wheels = [ [[package]] name = "urllib3" -version = "2.3.0" +version = "1.26.20" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 } +sdist = { url = "https://files.pythonhosted.org/packages/e4/e8/6ff5e6bc22095cfc59b6ea711b687e2b7ed4bdb373f7eeec370a97d7392f/urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32", size = 307380 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, + { url = "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e", size = 144225 }, ] [[package]] From 01768a23a52fe4c5bee53a75db38af2b708f4a4c Mon Sep 17 00:00:00 2001 From: saurabhsingh2974 Date: Wed, 25 Jun 2025 22:35:22 +0530 Subject: [PATCH 2/6] fixed for snowflake syncer for key-pair authentication The upgrated version of sqlalchemy module now handles p8 files at runtime, eliminating the need to serialize key-pair authentication files. This will help in key-pair authentication in snowflake Co-Authored-By: TS-sumeet-jain <168583077+TS-sumeet-jain@users.noreply.github.com> --- cs_tools/sync/snowflake/syncer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cs_tools/sync/snowflake/syncer.py b/cs_tools/sync/snowflake/syncer.py index f3c4461a..50879aee 100644 --- a/cs_tools/sync/snowflake/syncer.py +++ b/cs_tools/sync/snowflake/syncer.py @@ -88,7 +88,6 @@ def __repr__(self) -> str: # """ # from cryptography.hazmat.backends import default_backend # type: ignore # from cryptography.hazmat.primitives import serialization # type: ignore - # assert self.private_key_path is not None # pem_data = self.private_key_path.read_bytes() # passphrase = self.secret.encode() if self.secret is not None else self.secret From 355132aa050135430da307e7b70ee0c890055abd Mon Sep 17 00:00:00 2001 From: saurabhsingh2974 Date: Fri, 19 Sep 2025 14:03:43 +0530 Subject: [PATCH 3/6] Added AI and BI Stats model to searchable + make concurrency configurable 1.Added the TS: AI and BI Stats model to the list of searchable models. 2.Made the concurrent call limit dynamic, with a configurable option (default set to 15). --- cs_tools/cli/commands/config.py | 6 ++ .../cli/tools/searchable/api_transformer.py | 78 ++++++++++++++ cs_tools/cli/tools/searchable/app.py | 102 ++++++++++++++++++ cs_tools/cli/tools/searchable/models.py | 66 ++++++++++++ cs_tools/thoughtspot.py | 2 +- 5 files changed, 253 insertions(+), 1 deletion(-) diff --git a/cs_tools/cli/commands/config.py b/cs_tools/cli/commands/config.py index d88979c0..afa31545 100644 --- a/cs_tools/cli/commands/config.py +++ b/cs_tools/cli/commands/config.py @@ -44,6 +44,7 @@ def create( None, help="the password you type on the ThoughtSpot login screen, use [b magenta]prompt[/] to type it hidden" ), secret: str = typer.Option(None, help="the trusted authentication secret key, found in the developer tab"), + concurrency: int = typer.Option(None, help="change the number call sending to TS, By default 15"), token: str = typer.Option(None, help="the V2 API bearer token"), default_org: int = typer.Option(None, help="org ID to sign into by default"), temp_dir: custom_types.Directory = typer.Option(None, help="the temporary directory to use for uploading files"), @@ -80,6 +81,7 @@ def create( "default_org": default_org, "disable_ssl": disable_ssl, "proxy": proxy, + "concurrency": concurrency, }, "verbose": verbose, "temp_dir": temp_dir or cs_tools_venv.subdir(".tmp"), @@ -117,6 +119,7 @@ def modify( ), secret: str = typer.Option(None, help="the trusted authentication secret key"), token: str = typer.Option(None, help="the V2 API bearer token"), + concurrency: int = typer.Option(None, help="change the number call sending to TS, By default 15"), temp_dir: custom_types.Directory = typer.Option(None, help="the temporary directory to use for uploading files"), disable_ssl: bool = typer.Option( None, "--disable-ssl", help="whether or not to turn off checking the SSL certificate" @@ -162,6 +165,9 @@ def modify( if proxy is not None: data["thoughtspot"]["proxy"] = proxy + if concurrency is not None: + data["thoughtspot"]["concurrency"] = concurrency + conf = CSToolsConfig.model_validate(data) conf.save() diff --git a/cs_tools/cli/tools/searchable/api_transformer.py b/cs_tools/cli/tools/searchable/api_transformer.py index cdcf0ba1..5d852a83 100644 --- a/cs_tools/cli/tools/searchable/api_transformer.py +++ b/cs_tools/cli/tools/searchable/api_transformer.py @@ -665,3 +665,81 @@ def ts_audit_logs(data: list[_types.APIResult], *, cluster: _types.GUID) -> _typ reshaped.sort(key=operator.itemgetter(*CLUSTER_KEY)) return reshaped + + +def ts_ai_stats(data: list[_types.APIResult], *, cluster: _types.GUID) -> _types.TableRowsFormat: + """Reshapes /searchdata -> searchable.models.BIServer.""" + reshaped: _types.TableRowsFormat = [] + + PARTITION_KEY = ft.partial(lambda r: r["ThoughtSpot Start Time"].date()) + CLUSTER_KEY = ("ThoughtSpot Start Time", "User ID", "Visualization ID") + + # KEEP TRACK OF DUPLICATE ROWS DUE TO DATA MANAGEMENT ISSUES. + seen: set[str] = set() + + # ENSURE ALL DATA IS IN UTC PRIOR TO GENERATING ROW_NUMBERS. + data = [{**row, "ThoughtSpot Start Time": validators.ensure_datetime_is_utc.func(row["ThoughtSpot Start Time"])} for row in data] + + # SORT PRIOR TO GROUP BY SO WE MAINTAIN CLUSTERING KEY SEMANTICS + data.sort(key=operator.itemgetter(*CLUSTER_KEY)) + + for row_date, rows in it.groupby(data, key=PARTITION_KEY): + # MANUAL ENUMERATION BECAUSE WE NEED TO ACCOUNT FOR DEDUPLICATION. + row_number = 0 + + for row in rows: + if (unique := f"{row['ThoughtSpot Start Time']}-{row['User ID']}-{row['Visualization ID']}") in seen: + continue + + row_number += 1 + + reshaped.append( + models.AIStats.validated_init( + **{ + "cluster_guid": cluster, + "sk_dummy": f"{cluster}-{row_date}-{row_number}", + "answer_session_id" : row["Answer Session ID"], + "query_latency" : row["Average Query Latency (External)"], + "system_latency" : row["Average System Latency (Overall)"], + "connection" : row["Connection"], + "connection_id" : row["Connection ID"], + "db_auth_type" : row["DB Auth Type"], + "db_type" : row["DB Type"], + "error_message" : row["Error Message"], + "external_database_query_id" : row["External Database Query ID"], + "impressions" : row["Impressions"], + "is_billable" : row["Is Billable"], + "is_system" : row["Is System"], + "model" : row["Model"], + "model_id" : row["Model ID"], + "object" : row["Object"], + "object_id" : row["Object ID"], + "object_subtype" : row["Object Subtype"], + "object_type" : row["Object Type"], + "org" : row["Org"], + "org_id" : row["Org ID"], + "query_count" : row["Query Count"], + "query_end_time" : row["Query End Time"], + "query_errors" : row["Query Errors"], + "query_start_time" : row["Query Start Time"], + "query_status" : row["Query Status"], + "sql_query" : row["SQL Query"], + "thoughtspot_query_id" : row["ThoughtSpot Query ID"], + "thoughtspot_start_time" : row["ThoughtSpot Start Time"], + "credits" : row["Total Credits"], + "nums_rows_fetched" : row["Total Nums Rows Fetched"], + "trace_id" : row["Trace ID"], + "user" : row["User"], + "user_action" : row["User Action"], + "user_action_count" : row["User Action Count"], + "user_count" : row["User Count"], + "user_display_name" : row["User Display Name"], + "user_id" : row["User ID"], + "visualization_id" : row["Visualization ID"], + } + ).model_dump() + ) + + seen.add(unique) + + return reshaped \ No newline at end of file diff --git a/cs_tools/cli/tools/searchable/app.py b/cs_tools/cli/tools/searchable/app.py index cc2395f9..425b7ee6 100644 --- a/cs_tools/cli/tools/searchable/app.py +++ b/cs_tools/cli/tools/searchable/app.py @@ -375,6 +375,8 @@ def metadata( """ ts = ctx.obj.thoughtspot + print(ts.__dict__.get('config').thoughtspot.concurrency) + if not ts.session_context.user.is_admin: log.warning("Searchable is meant to be run from an Admin-level context, your results may vary..") @@ -773,3 +775,103 @@ def tml( syncer.dump(models.MetadataTML.__tablename__, data=rows) return 0 + +@app.command() +@depends_on(thoughtspot=ThoughtSpot()) +def ts_ai_stats( + ctx: typer.Context, + syncer: Syncer = typer.Option( + ..., + click_type=custom_types.Syncer(models=[models.AIStats]), + help="protocol and path for options to pass to the syncer", + rich_help_panel="Syncer Options", + ), + from_date: custom_types.Date = typer.Option(..., help="inclusive lower bound of rows to select from TS: BI Server"), + to_date: custom_types.Date = typer.Option(..., help="inclusive upper bound of rows to select from TS: BI Server"), + org_override: str = typer.Option(None, "--org", help="The Org to switch to before performing actions."), + compact: bool = typer.Option(True, "--compact / --full", help="If compact, add [User Action] != {null} 'invalid'"), +) -> _types.ExitCode: + """ + Extract query performance metrics for each query made against an external database + + To extract one day of data, set [b cyan]--from-date[/] and [b cyan]--to-date[/] to the same value. + \b + Fields extracted from TS: AI and BI Stats + - Answer Session ID - Average Query Latency (External) - Average System Latency (Overall) - Impressions + - Connection - Connection ID - DB Auth Type - Is System + - DB Type - Error Message - External Database Query ID - Is Billable + - Model - Model ID - Object - Object ID + - Object Subtype - Object Type - Org - Org ID + - Query Count - Query End Time - Query Errors - Query Start Time + - Query Status - SQL Query - ThoughtSpot Query ID - ThoughtSpot Start Time + - Total Credits - Total Nums Rows Fetched - Trace ID - User + - User Action - User Action Count - User Count - User Display Name + - User ID - Visualization ID + """ + assert isinstance(from_date, dt.date), f"Could not coerce from_date '{from_date}' to a date." + assert isinstance(to_date, dt.date), f"Could not coerce to_date '{to_date}' to a date." + ts = ctx.obj.thoughtspot + + CLUSTER_UUID = ts.session_context.thoughtspot.cluster_id + + TZ_UTC = zoneinfo.ZoneInfo("UTC") + TS_AI_TIMEZONE = TZ_UTC if ts.session_context.thoughtspot.is_cloud else ts.session_context.thoughtspot.timezone + print(f"TS_AI_TIMEZONE -> {TS_AI_TIMEZONE}") + + if syncer.protocol == "falcon": + log.error("Falcon Syncer is not supported for TS: AI Server reflection.") + models.AIStats.__table__.drop(syncer.engine) + return 1 + + if (to_date - from_date) > dt.timedelta(days=31): # type: ignore[operator] + log.warning("Due to how the Search API functions, it's recommended to request no more than 1 month at a time.") + + # DEV NOTE: @boonhapus + # As of 9.10.0.cl , TS: BI Server only resides in the Primary Org(0), so switch to it + if ts.session_context.thoughtspot.is_orgs_enabled: + ts.switch_org(org_id=0) + + if org_override is not None: + c = workflows.metadata.fetch_one(identifier=org_override, metadata_type="ORG", attr_path="id", http=ts.api) + _ = utils.run_sync(c) + org_override = _ + + SEARCH_DATA_DATE_FMT = "%m/%d/%Y" + SEARCH_TOKENS = ( + "[Query Start Time] [Query Start Time].detailed [Query End Time] [Query End Time].detailed [Org]" + "[Query Status] [Connection] [User] [Nums Rows Fetched] [ThoughtSpot Query ID] [Is Billable] [ThoughtSpot Start Time]" + "[ThoughtSpot Start Time].detailed [User Action] [Is System] [Visualization ID] [External Database Query ID] [Query Latency (External)] " + "[Object] [User ID] [Org ID] [Credits] [Impressions] [Query Count] [Query Errors] [System Latency (Overall)] [User Action Count]" + "[User Action Count] [User Count] [Answer Session ID] [Connection ID] [DB Auth Type] [DB Type] [Error Message] [Model]" + "[Model ID] [Object ID] [Object Subtype] [Object Type] [SQL Query] [User Display Name] [Trace ID]" + "[ThoughtSpot Start Time].detailed [ThoughtSpot Start Time] != 'today'" + # FOR DATA QUALITY PURPOSES + # CONDITIONALS BASED ON CLI OPTIONS OR ENVIRONMENT + + ("" if not compact else " [user action] != [user action].invalid [user action].{null}") + + ("" if from_date is None else f" [ThoughtSpot Start Time] >= '{from_date.strftime(SEARCH_DATA_DATE_FMT)}'") + + ("" if to_date is None else f" [ThoughtSpot Start Time] <= '{to_date.strftime(SEARCH_DATA_DATE_FMT)}'") + + ("" if not ts.session_context.thoughtspot.is_orgs_enabled else " [org id]") + + ("" if org_override is None else f" [org id] = {org_override}") + ) + + TOOL_TASKS = [ + px.WorkTask(id="SEARCH", description="Fetching data from ThoughtSpot"), + px.WorkTask(id="CLEAN", description="Transforming API results"), + px.WorkTask(id="DUMP_DATA", description=f"Sending data to {syncer.name}"), + ] + + # DEV NOTE: @saurabhsingh1608. 09/15/2025 + # Currently worksheet name is "TS: AI and BI Stats (Beta)" change it in future as need arise + + with px.WorkTracker("Fetching TS: AI and BI Stats", tasks=TOOL_TASKS) as tracker: + with tracker["SEARCH"]: + c = workflows.search(worksheet="TS: AI and BI Stats (Beta)", query=SEARCH_TOKENS, timezone=TS_AI_TIMEZONE, http=ts.api) + _ = utils.run_sync(c) + + with tracker["CLEAN"]: + d = api_transformer.ts_ai_stats(data=_, cluster=CLUSTER_UUID) + + with tracker["DUMP_DATA"]: + syncer.dump("ts_ai_stats", data=d) + + return 0 \ No newline at end of file diff --git a/cs_tools/cli/tools/searchable/models.py b/cs_tools/cli/tools/searchable/models.py index 49ffb6bd..45f9a688 100644 --- a/cs_tools/cli/tools/searchable/models.py +++ b/cs_tools/cli/tools/searchable/models.py @@ -365,6 +365,72 @@ def export_reserved_characters_are_escaped(self, query_text: Optional[str]) -> O return query_text +class AIStats(ValidatedSQLModel, table=True): + __tablename__ = "ts_ai_stats" + cluster_guid: str = Field(primary_key=True) + sk_dummy: str = Field(primary_key=True) + answer_session_id : Optional[str] + query_latency : Optional[int] + system_latency : Optional[int] + connection : Optional[str] + connection_id : Optional[str] + db_auth_type : Optional[str] + db_type : Optional[str] + error_message : Optional[str] + external_database_query_id : Optional[str] + impressions : Optional[int] + is_billable : Optional[bool] + is_system : Optional[bool] + model : Optional[str] + model_id : Optional[str] + object : Optional[str] + object_id : Optional[str] + object_subtype : Optional[str] + object_type : Optional[str] + org : Optional[str] + org_id: int = 0 + query_count : Optional[int] + query_end_time : dt.datetime = Field(sa_column = Column(TIMESTAMP)) + query_errors : Optional[int] + query_start_time : dt.datetime = Field(sa_column =Column(TIMESTAMP)) + query_status : Optional[str] + sql_query : Optional[str] = Field(sa_column = Column(Text, info = {"length_override": "MAX"})) + thoughtspot_query_id :Optional[str] + thoughtspot_start_time : dt.datetime = Field(sa_column =Column(TIMESTAMP)) + credits : Optional[int] + nums_rows_fetched : Optional[int] + trace_id : Optional[str] + user : Optional[str] + user_action : Optional[str] + user_action_count : Optional[int] + user_count : Optional[int] + user_display_name : Optional[str] + user_id : Optional[str] + visualization_id : Optional[str] + + + @pydantic.field_validator("thoughtspot_start_time", mode="before") + @classmethod + def check_valid_utc_datetime(cls, value: Any) -> dt.datetime: + return validators.ensure_datetime_is_utc.func(value) + + @pydantic.field_validator("user_action", mode="after") + @classmethod + def ensure_is_case_sensitive_thoughtspot_enum_value(cls, value: Optional[str]) -> Optional[str]: + # Why not Annotated[str, pydantic.StringContraints(to_upper=True)] ? + # sqlmodel#67: https://github.com/tiangolo/sqlmodel/issues/67 + return None if value is None else value.upper() + + @pydantic.field_serializer("sql_query") + def export_reserved_characters_are_escaped(self, sql_query: Optional[str]) -> Optional[str]: + if sql_query is None: + return sql_query + reserved_characters = ("\\",) + + for character in reserved_characters: + sql_query = sql_query.replace(character, f"\\{character}") + + return sql_query METADATA_MODELS = [ Cluster, diff --git a/cs_tools/thoughtspot.py b/cs_tools/thoughtspot.py index 59682354..2dcb9728 100644 --- a/cs_tools/thoughtspot.py +++ b/cs_tools/thoughtspot.py @@ -28,7 +28,7 @@ def __init__(self, config: CSToolsConfig, auto_login: bool = False): self.config = config self.api = RESTAPIClient( base_url=str(config.thoughtspot.url), - concurrency=15, + concurrency= 15 if config.thoughtspot.concurrency is None else config.thoughtspot.concurrency, # cache_directory=config.temp_dir, verify=not config.thoughtspot.disable_ssl, proxy=config.thoughtspot.proxy, From 030e2e43a7851fd20c0b363a58082a1ecabe3485 Mon Sep 17 00:00:00 2001 From: saurabhsingh2974 Date: Fri, 19 Sep 2025 14:32:56 +0530 Subject: [PATCH 4/6] Update app.py Co-Authored-By: Sumeet(Sam) <33768055+SameerJain901@users.noreply.github.com> --- cs_tools/cli/tools/searchable/app.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cs_tools/cli/tools/searchable/app.py b/cs_tools/cli/tools/searchable/app.py index 425b7ee6..9abfef68 100644 --- a/cs_tools/cli/tools/searchable/app.py +++ b/cs_tools/cli/tools/searchable/app.py @@ -375,8 +375,6 @@ def metadata( """ ts = ctx.obj.thoughtspot - print(ts.__dict__.get('config').thoughtspot.concurrency) - if not ts.session_context.user.is_admin: log.warning("Searchable is meant to be run from an Admin-level context, your results may vary..") From 165ffcfb0234d383acf029d2e14f0f02f1cdcf43 Mon Sep 17 00:00:00 2001 From: saurabhsingh2974 Date: Fri, 19 Sep 2025 14:34:06 +0530 Subject: [PATCH 5/6] Update pyproject.toml Co-Authored-By: Sumeet(Sam) <33768055+SameerJain901@users.noreply.github.com> --- pyproject.toml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 867dbb7f..57a50932 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,10 +56,6 @@ dependencies = [ "exceptiongroup; python_version < '3.11.0'", "strenum; python_version < '3.11.0'", "taskgroup; python_version < '3.11.0'", - "typer>=0.12.0", - "prompt-toolkit>=3.0.47", - "textual-serve>=1.1.1", - "snowflake-sqlalchemy>=1.7.4", ] [project.urls] @@ -216,4 +212,4 @@ sqlmodel = "sm" combine-as-imports = true force-wrap-aliases = true from-first = true -required-imports = ["from __future__ import annotations"] +required-imports = ["from __future__ import annotations"] \ No newline at end of file From 68b84ce955c818d208092f0dfafdb51e4ce75019 Mon Sep 17 00:00:00 2001 From: saurabhsingh2974 <164007629+saurabhsingh2974@users.noreply.github.com> Date: Fri, 19 Sep 2025 16:12:36 +0530 Subject: [PATCH 6/6] Update uv.lock --- uv.lock | 209 ++++---------------------------------------------------- 1 file changed, 12 insertions(+), 197 deletions(-) diff --git a/uv.lock b/uv.lock index 0c336290..95ae6e4b 100644 --- a/uv.lock +++ b/uv.lock @@ -1,9 +1,5 @@ version = 1 requires-python = ">=3.9.2" -resolution-markers = [ - "python_full_version >= '3.10'", - "python_full_version < '3.10'", -] [[package]] name = "aiohappyeyeballs" @@ -173,15 +169,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/46/eb/e7f063ad1fec6b3178a3cd82d1a3c4de82cccf283fc42746168188e1cdd5/anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a", size = 96041 }, ] -[[package]] -name = "asn1crypto" -version = "1.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/de/cf/d547feed25b5244fcb9392e288ff9fdc3280b10260362fc45d37a798a6ee/asn1crypto-1.5.1.tar.gz", hash = "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c", size = 121080 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c9/7f/09065fd9e27da0eda08b4d6897f1c13535066174cc023af248fc2a8d5e5a/asn1crypto-1.5.1-py2.py3-none-any.whl", hash = "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67", size = 105045 }, -] - [[package]] name = "async-timeout" version = "5.0.1" @@ -285,34 +272,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646 }, ] -[[package]] -name = "boto3" -version = "1.38.36" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "botocore" }, - { name = "jmespath" }, - { name = "s3transfer" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c4/22/df130d30dcc73b726c3d254ed855806853b86b987052517337587085b6db/boto3-1.38.36.tar.gz", hash = "sha256:efe0aaa060f8fedd76e5c942055f051aee0432fc722d79d8830a9fd9db83593e", size = 111823 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/24/ce/f609adc7dfd53792a9b704aa1241f8e5f34c21a5364f64b114d7874f8327/boto3-1.38.36-py3-none-any.whl", hash = "sha256:34c27d7317cadb62c0e9856e5d5aa0271ef47202d340584831048bc7ac904136", size = 139938 }, -] - -[[package]] -name = "botocore" -version = "1.38.36" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jmespath" }, - { name = "python-dateutil" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2e/15/d218917f2d568f6fa92ad3831b31ecc4ee514d775a142385aa87c672bc08/botocore-1.38.36.tar.gz", hash = "sha256:4a1ced1a4218bdff0ed5b46abb54570d473154ddefafa5d121a8d96e4b76ebc1", size = 13966245 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/75/2d/3ccc58837b3ed8322a15b9fd94114a326e6ab29d36a37508aadf9cf7808e/botocore-1.38.36-py3-none-any.whl", hash = "sha256:b6a50b853f6d23af9edfed89a59800c6bc1687a947cdd3492879f7d64e002d30", size = 13623866 }, -] - [[package]] name = "certifi" version = "2025.1.31" @@ -476,14 +435,14 @@ wheels = [ [[package]] name = "click" -version = "8.1.7" +version = "8.1.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } +sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 }, + { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, ] [[package]] @@ -573,7 +532,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/91/4c/45dfa6829acffa344e3967d6006ee4ae8be57af746ae2eba1c431949b32c/cryptography-44.0.0.tar.gz", hash = "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02", size = 710657 } wheels = [ - { url = "https://files.pythonhosted.org/packages/55/09/8cc67f9b84730ad330b3b72cf867150744bf07ff113cda21a15a1c6d2c7c/cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123", size = 6541833 }, { url = "https://files.pythonhosted.org/packages/7e/5b/3759e30a103144e29632e7cb72aec28cedc79e514b2ea8896bb17163c19b/cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092", size = 3922710 }, { url = "https://files.pythonhosted.org/packages/5f/58/3b14bf39f1a0cfd679e753e8647ada56cddbf5acebffe7db90e184c76168/cryptography-44.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f", size = 4137546 }, { url = "https://files.pythonhosted.org/packages/98/65/13d9e76ca19b0ba5603d71ac8424b5694415b348e719db277b5edc985ff5/cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb", size = 3915420 }, @@ -581,9 +539,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/75/ea/af65619c800ec0a7e4034207aec543acdf248d9bffba0533342d1bd435e1/cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543", size = 3932569 }, { url = "https://files.pythonhosted.org/packages/c7/af/d1deb0c04d59612e3d5e54203159e284d3e7a6921e565bb0eeb6269bdd8a/cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e", size = 4016721 }, { url = "https://files.pythonhosted.org/packages/bd/69/7ca326c55698d0688db867795134bdfac87136b80ef373aaa42b225d6dd5/cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e", size = 4240915 }, - { url = "https://files.pythonhosted.org/packages/ef/d4/cae11bf68c0f981e0413906c6dd03ae7fa864347ed5fac40021df1ef467c/cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053", size = 2757925 }, - { url = "https://files.pythonhosted.org/packages/64/b1/50d7739254d2002acae64eed4fc43b24ac0cc44bf0a0d388d1ca06ec5bb1/cryptography-44.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd", size = 3202055 }, - { url = "https://files.pythonhosted.org/packages/11/18/61e52a3d28fc1514a43b0ac291177acd1b4de00e9301aaf7ef867076ff8a/cryptography-44.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591", size = 6542801 }, { url = "https://files.pythonhosted.org/packages/1a/07/5f165b6c65696ef75601b781a280fc3b33f1e0cd6aa5a92d9fb96c410e97/cryptography-44.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7", size = 3922613 }, { url = "https://files.pythonhosted.org/packages/28/34/6b3ac1d80fc174812486561cf25194338151780f27e438526f9c64e16869/cryptography-44.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc", size = 4137925 }, { url = "https://files.pythonhosted.org/packages/d0/c7/c656eb08fd22255d21bc3129625ed9cd5ee305f33752ef2278711b3fa98b/cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289", size = 3915417 }, @@ -591,42 +546,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a2/cd/2f3c440913d4329ade49b146d74f2e9766422e1732613f57097fea61f344/cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c", size = 3932331 }, { url = "https://files.pythonhosted.org/packages/7f/df/8be88797f0a1cca6e255189a57bb49237402b1880d6e8721690c5603ac23/cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64", size = 4017372 }, { url = "https://files.pythonhosted.org/packages/af/36/5ccc376f025a834e72b8e52e18746b927f34e4520487098e283a719c205e/cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285", size = 4239657 }, - { url = "https://files.pythonhosted.org/packages/46/b0/f4f7d0d0bcfbc8dd6296c1449be326d04217c57afb8b2594f017eed95533/cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417", size = 2758672 }, - { url = "https://files.pythonhosted.org/packages/97/9b/443270b9210f13f6ef240eff73fd32e02d381e7103969dc66ce8e89ee901/cryptography-44.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede", size = 3202071 }, - { url = "https://files.pythonhosted.org/packages/77/d4/fea74422326388bbac0c37b7489a0fcb1681a698c3b875959430ba550daa/cryptography-44.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731", size = 3338857 }, { url = "https://files.pythonhosted.org/packages/1a/aa/ba8a7467c206cb7b62f09b4168da541b5109838627f582843bbbe0235e8e/cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4", size = 3850615 }, { url = "https://files.pythonhosted.org/packages/89/fa/b160e10a64cc395d090105be14f399b94e617c879efd401188ce0fea39ee/cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756", size = 4081622 }, { url = "https://files.pythonhosted.org/packages/47/8f/20ff0656bb0cf7af26ec1d01f780c5cfbaa7666736063378c5f48558b515/cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c", size = 3867546 }, { url = "https://files.pythonhosted.org/packages/38/d9/28edf32ee2fcdca587146bcde90102a7319b2f2c690edfa627e46d586050/cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa", size = 4090937 }, - { url = "https://files.pythonhosted.org/packages/cc/9d/37e5da7519de7b0b070a3fedd4230fe76d50d2a21403e0f2153d70ac4163/cryptography-44.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c", size = 3128774 }, ] [[package]] name = "cs-tools" -version = "1.6.4" +version = "1.6.3" source = { editable = "." } dependencies = [ { name = "aiosqlite" }, { name = "awesomeversion" }, { name = "betterproto", extra = ["compiler"] }, - { name = "click" }, { name = "email-validator" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "httpx" }, { name = "packaging" }, - { name = "prompt-toolkit" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "rich" }, - { name = "snowflake-sqlalchemy" }, { name = "sqlmodel" }, { name = "strenum", marker = "python_full_version < '3.11'" }, { name = "taskgroup", marker = "python_full_version < '3.11'" }, { name = "tenacity" }, - { name = "textual-serve" }, { name = "thoughtspot-tml" }, { name = "toml" }, - { name = "typer" }, { name = "typing-extensions", marker = "python_full_version < '3.10'" }, { name = "tzdata", marker = "sys_platform == 'win32'" }, ] @@ -670,7 +616,6 @@ requires-dist = [ { name = "aiosqlite" }, { name = "awesomeversion" }, { name = "betterproto", extras = ["compiler"], specifier = "==2.0.0b6" }, - { name = "click", specifier = "==8.1.7" }, { name = "coverage", extras = ["toml"], marker = "extra == 'dev'" }, { name = "email-validator" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, @@ -682,7 +627,6 @@ requires-dist = [ { name = "mypy", marker = "extra == 'dev'" }, { name = "packaging" }, { name = "pre-commit", marker = "extra == 'dev'" }, - { name = "prompt-toolkit", specifier = ">=3.0.47" }, { name = "prompt-toolkit", marker = "extra == 'cli'", specifier = "==3.0.47" }, { name = "prompt-toolkit", marker = "extra == 'dev'", specifier = "==3.0.47" }, { name = "prompt-toolkit", marker = "extra == 'docs'", specifier = "==3.0.47" }, @@ -690,9 +634,8 @@ requires-dist = [ { name = "pydantic-settings" }, { name = "pytest", marker = "extra == 'dev'" }, { name = "python-slugify", extras = ["unidecode"], marker = "extra == 'docs'" }, - { name = "rich", specifier = "==13.7.1" }, + { name = "rich", specifier = ">=13.7.1" }, { name = "ruff", marker = "extra == 'dev'" }, - { name = "snowflake-sqlalchemy", specifier = ">=1.7.4" }, { name = "sqlmodel", specifier = ">=0.0.16" }, { name = "strenum", marker = "python_full_version < '3.11'" }, { name = "taskgroup", marker = "python_full_version < '3.11'" }, @@ -701,13 +644,11 @@ requires-dist = [ { name = "textual", extras = ["syntax"], marker = "extra == 'dev'", specifier = "==1.0.0" }, { name = "textual", extras = ["syntax"], marker = "extra == 'docs'", specifier = "==1.0.0" }, { name = "textual-dev", marker = "extra == 'dev'", specifier = ">=1.7.0" }, - { name = "textual-serve", specifier = ">=1.1.1" }, { name = "textual-serve", marker = "extra == 'cli'", specifier = "==1.1.1" }, { name = "textual-serve", marker = "extra == 'dev'", specifier = "==1.1.1" }, { name = "textual-serve", marker = "extra == 'docs'", specifier = "==1.1.1" }, { name = "thoughtspot-tml" }, { name = "toml" }, - { name = "typer", specifier = ">=0.12.0" }, { name = "typer", marker = "extra == 'cli'", specifier = "==0.12.0" }, { name = "typer", marker = "extra == 'dev'", specifier = "==0.12.0" }, { name = "typer", marker = "extra == 'docs'", specifier = "==0.12.0" }, @@ -1162,15 +1103,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596 }, ] -[[package]] -name = "jmespath" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256 }, -] - [[package]] name = "keyring" version = "25.6.0" @@ -1972,15 +1904,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, ] -[[package]] -name = "pyjwt" -version = "2.10.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997 }, -] - [[package]] name = "pymdown-extensions" version = "10.14.3" @@ -1994,19 +1917,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/eb/f5/b9e2a42aa8f9e34d52d66de87941ecd236570c7ed2e87775ed23bbe4e224/pymdown_extensions-10.14.3-py3-none-any.whl", hash = "sha256:05e0bee73d64b9c71a4ae17c72abc2f700e8bc8403755a00580b49a4e9f189e9", size = 264467 }, ] -[[package]] -name = "pyopenssl" -version = "25.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cryptography" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/04/8c/cd89ad05804f8e3c17dea8f178c3f40eeab5694c30e0c9f5bcd49f576fc3/pyopenssl-25.1.0.tar.gz", hash = "sha256:8d031884482e0c67ee92bf9a4d8cceb08d92aba7136432ffb0703c5280fc205b", size = 179937 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/80/28/2659c02301b9500751f8d42f9a6632e1508aa5120de5e43042b8b30f8d5d/pyopenssl-25.1.0-py3-none-any.whl", hash = "sha256:2b11f239acc47ac2e5aca04fd7fa829800aeee22a2eb30d744572a157bd8a1ab", size = 56771 }, -] - [[package]] name = "pytest" version = "8.3.4" @@ -2062,15 +1972,6 @@ unidecode = [ { name = "unidecode" }, ] -[[package]] -name = "pytz" -version = "2025.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225 }, -] - [[package]] name = "pywin32-ctypes" version = "0.2.3" @@ -2247,15 +2148,16 @@ wheels = [ [[package]] name = "rich" -version = "13.7.1" +version = "13.9.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b3/01/c954e134dc440ab5f96952fe52b4fdc64225530320a910473c1fe270d9aa/rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432", size = 221248 } +sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/67/a37f6214d0e9fe57f6ae54b2956d550ca8365857f42a1ce0392bb21d9410/rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222", size = 240681 }, + { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, ] [[package]] @@ -2283,18 +2185,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/75/d9/fde7610abd53c0c76b6af72fc679cb377b27c617ba704e25da834e0a0608/ruff-0.9.5-py3-none-win_arm64.whl", hash = "sha256:18a29f1a005bddb229e580795627d297dfa99f16b30c7039e73278cf6b5f9fa9", size = 10064595 }, ] -[[package]] -name = "s3transfer" -version = "0.13.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "botocore" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ed/5d/9dcc100abc6711e8247af5aa561fc07c4a046f72f659c3adea9a449e191a/s3transfer-0.13.0.tar.gz", hash = "sha256:f5e6db74eb7776a37208001113ea7aa97695368242b364d73e91c981ac522177", size = 150232 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/17/22bf8155aa0ea2305eefa3a6402e040df7ebe512d1310165eda1e233c3f8/s3transfer-0.13.0-py3-none-any.whl", hash = "sha256:0148ef34d6dd964d0d8cf4311b2b21c474693e57c2e069ec708ce043d2b527be", size = 85152 }, -] - [[package]] name = "secretstorage" version = "3.3.3" @@ -2335,81 +2225,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] -[[package]] -name = "snowflake-connector-python" -version = "3.15.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "asn1crypto" }, - { name = "boto3" }, - { name = "botocore" }, - { name = "certifi" }, - { name = "cffi" }, - { name = "charset-normalizer" }, - { name = "cryptography" }, - { name = "filelock" }, - { name = "idna" }, - { name = "packaging" }, - { name = "platformdirs" }, - { name = "pyjwt" }, - { name = "pyopenssl" }, - { name = "pytz" }, - { name = "requests" }, - { name = "sortedcontainers" }, - { name = "tomlkit" }, - { name = "typing-extensions" }, - { name = "urllib3", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/99/ff/7c1b2cbb5a43b21abebfa58c83926266e9f5ea05123e795753da6ce84f96/snowflake_connector_python-3.15.0.tar.gz", hash = "sha256:1ef52e2fb3ecc295139737d3d759f85d962ef7278c6990c3bd9c17fcb82508d6", size = 774355 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/97/eb/9c01764355928258f57663e8f9eacf608b8e03dc093cbcb69244e2ad5de8/snowflake_connector_python-3.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ef92f4ceb61b6a7373ec417f7201d288a6a5a3a42b7e789d3b2221b4dff5ed3c", size = 989157 }, - { url = "https://files.pythonhosted.org/packages/5e/b1/35b31eb3b3303f1d29815a8b28e89d399ea2600933f5a6343943f851c2bd/snowflake_connector_python-3.15.0-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:d33bd2b326d6ea4d49e0cd821f75b3c5f2910be21f4575c1a03d272af78af767", size = 1001262 }, - { url = "https://files.pythonhosted.org/packages/da/e4/7d0a22fd535e15f9625b5726a2a80d53fcb30eb658defff71f93bd536f7c/snowflake_connector_python-3.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56fe48836c5dcda71b951f3f586c036631f7e3d17c3e201489c56974eea5e665", size = 2565688 }, - { url = "https://files.pythonhosted.org/packages/2b/47/1d5bff17d6237f0d0863eae6cfeb85b92a1ec2e95ffae579b0b5b0886e2e/snowflake_connector_python-3.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9345591a62e99f811af6dca758fde873660ced3b4e60a77716f6f2d75b609fd9", size = 2589247 }, - { url = "https://files.pythonhosted.org/packages/79/fe/c0a84498ede55fd48bf21beb855e5a9b0d1cc76b3c8210a989de990b533b/snowflake_connector_python-3.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:21243f2296ceeb238eff871443379665f72125c2086032b40e85ff576df8cc0a", size = 948426 }, - { url = "https://files.pythonhosted.org/packages/af/e6/813f6b299f23f952996da4b4f0f8dade52d5b0f5db516c957b236120cee8/snowflake_connector_python-3.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d6c22820806b43c9f9c5ae3c7758307fb668c42b7ddf74d995b2f0d2da21f08e", size = 989306 }, - { url = "https://files.pythonhosted.org/packages/3e/cf/38dd6ef6bb1a01ab591986b6b903df7f9f4dbb2467b058bebb6ddd4342a3/snowflake_connector_python-3.15.0-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:f83b2e08d29f1bb61c7152bf87f0b8a9e77ee25f09e506f69085a365fe8825df", size = 1001394 }, - { url = "https://files.pythonhosted.org/packages/53/cf/fbf21bc506c032d4a104faf0ced7cbbe6dfecc13e96dd1e211b9c48a08c0/snowflake_connector_python-3.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dbd35265af54ad045cadbed5bfbc76816d2e4d95902f3312365d54c08a33ec3", size = 2590253 }, - { url = "https://files.pythonhosted.org/packages/30/5e/3b325c21e91df06b1868c791f384efd44b142c6d777f9c9322148ccb0a05/snowflake_connector_python-3.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b8757b6206982e784a8f9f24a6fd3de4849e37113788ef677373b6b18907e91", size = 2612009 }, - { url = "https://files.pythonhosted.org/packages/42/d3/9e5125f3a5dac2b8327ad3cb0268842deda8e0b28263320ca752926ce3b2/snowflake_connector_python-3.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:f8994bcfdcd4915b0a365969346939d17ee03e041202048c0d108629bd598d4d", size = 948541 }, - { url = "https://files.pythonhosted.org/packages/bc/be/9b0573ccca48ea97677f326bd367804416691130cd1b9ef84968e8620ae3/snowflake_connector_python-3.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8f41ab707792b07c58214b13e7a6b50d4460f7151e19ea80df3612c92d3a7b76", size = 988559 }, - { url = "https://files.pythonhosted.org/packages/21/d7/6021da04416be8a07a6063038c9d532f583e59cfd14f1bf80bcee34d1f76/snowflake_connector_python-3.15.0-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:d2f0bb00a48c4125090dfe2e8bd15f9389be7867fd9e3c118ecb8dc87c69bcb8", size = 999857 }, - { url = "https://files.pythonhosted.org/packages/1b/de/d4fbd1cfc89e61614ee1963edcd9711369cb6ffea63c4c8d68c3fb248e1a/snowflake_connector_python-3.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:457408eeb4116f73df60bb912fdeb7f6d4849e2cfd7e282b2afb25f080f20188", size = 2602453 }, - { url = "https://files.pythonhosted.org/packages/92/09/6656444e9ff6d83bd1b2c73d1f6b6aab78ff67889e6e3744c8462c74c76f/snowflake_connector_python-3.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63e93f67712260a11ae3bb858c567be805aca5f96d042ff5feacea102a33b49f", size = 2626597 }, - { url = "https://files.pythonhosted.org/packages/c5/04/0b2edacbc7192d8d6a04ca17b81900099c835279157f05c2bac971dc77d2/snowflake_connector_python-3.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:acbceae9120502613991b9997d94cc23ea7e76cdfc3601718025f9f0859cc21e", size = 947264 }, - { url = "https://files.pythonhosted.org/packages/e7/b7/ca38fd1494918e47d23eaa7e3ce883bde5481e7031968894208d5cf726d4/snowflake_connector_python-3.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:52dbe588f7784f194caa739cb394557b81d150f21841d3b51d6d164f1b2e90c0", size = 988902 }, - { url = "https://files.pythonhosted.org/packages/3a/79/22fddcfece8a9813f953b5300e6795ff2cf1744afd0d162001fecffb681a/snowflake_connector_python-3.15.0-cp313-cp313-macosx_11_0_x86_64.whl", hash = "sha256:fcf4090514cc4c8be8f11573b7ed19f6fe6339048271cbdbc18c50a608b57655", size = 1000262 }, - { url = "https://files.pythonhosted.org/packages/9e/bb/7b4d3ea222cbda0f2c2e1825d3599d93512d000bb6c7eecb2a82b6c32511/snowflake_connector_python-3.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64418f6055789a6d1393dfbd3a609e126a88cd015065fad1923ef7b6f4b8dd61", size = 2607481 }, - { url = "https://files.pythonhosted.org/packages/a0/f4/8c820711011b3638c6992609698bcc67dbfb16e93141573e91048f99b505/snowflake_connector_python-3.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9df04e2294605d1e243793b5d889a250d6a301fea8b25c7a84703e3a709a96c", size = 2632032 }, - { url = "https://files.pythonhosted.org/packages/f7/6a/edb52a71b53b9d6d0208ebf47bbe96dab3979da01b6f74eda43232cc1fc2/snowflake_connector_python-3.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ecc5f570000ad957e09517d317ca07645ece77ca9befc88797439164e632738d", size = 989831 }, - { url = "https://files.pythonhosted.org/packages/74/26/dd71a6396b7d606a171433247ae837ae8eb728f4d14971c837f6d3e3a6c0/snowflake_connector_python-3.15.0-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:49e68d5130f17bde2de82bf1c7298803b4ec5bfb926a5daa9001542d710026bc", size = 1001799 }, - { url = "https://files.pythonhosted.org/packages/e2/cb/f965db23e288e8311439adb2b5ee64bc7bb7fa4adcdc34d391ccda92c477/snowflake_connector_python-3.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:698d9dbdd8873daaae01a46ca5d57caf3e4637a30a6afe5ca54cd0c460c359fd", size = 2566380 }, - { url = "https://files.pythonhosted.org/packages/e9/7c/86f80dddf7e895ee4174d0061492b83bfddb346416c071f8d680a147c76f/snowflake_connector_python-3.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04cadd3dae180a5f3632347c2a5836de7ac20fbdf8cb5192e021cad098c85247", size = 2589346 }, - { url = "https://files.pythonhosted.org/packages/82/db/fcd16bb08f478016309a5527f8f03522e2ee1b55a89839ca6b92d6fd9adb/snowflake_connector_python-3.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:0a97deeadfe746fb88475cb83498650e68cf051969476ea498f572e40d49ce96", size = 949123 }, -] - -[[package]] -name = "snowflake-sqlalchemy" -version = "1.7.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "snowflake-connector-python" }, - { name = "sqlalchemy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cb/68/7181c1cc714335f48f3c2685eed392045e9542aa6b1010462200b9921498/snowflake_sqlalchemy-1.7.4.tar.gz", hash = "sha256:a509ca0f11c5b19a242157189ad20a3ee9598aa391fcbac3ae3e6cf53251a6cb", size = 119579 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/5b/11f75dabb2fd0320ac73409963284723a9b14e3a7a90dbe9a6263ea1f50c/snowflake_sqlalchemy-1.7.4-py3-none-any.whl", hash = "sha256:52e14adf13640ff5543c32a4f0600fdb1e49c5862413ba5e27b08693c8676f82", size = 70507 }, -] - -[[package]] -name = "sortedcontainers" -version = "2.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, -] - [[package]] name = "sqlalchemy" version = "2.0.38" @@ -3030,11 +2845,11 @@ wheels = [ [[package]] name = "urllib3" -version = "1.26.20" +version = "2.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/e8/6ff5e6bc22095cfc59b6ea711b687e2b7ed4bdb373f7eeec370a97d7392f/urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32", size = 307380 } +sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e", size = 144225 }, + { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, ] [[package]]