refactor(auth&metrics): use accounts everywhere and switch metrics (#166)

* feat(metrics): wip

* refactor(auth): use accts instead of tokens

* fix(wrapper): delayed auth bug

* refactor(memory): quick fix

* fix(creds): change incompatible py 3.8+ syntax

* feat(anatylics): updates tracking

* fix(credentials): catch when no accts

* fix(metrics): remove unused field

* feat(wrapper): raise exception for old import

* feat(analytics): consolidate names
This commit is contained in:
izzy lyseggen 2022-02-23 11:00:04 +00:00 коммит произвёл GitHub
Родитель 21f13c4750
Коммит 944e70221e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
20 изменённых файлов: 720 добавлений и 339 удалений

229
poetry.lock сгенерированный
Просмотреть файл

@ -79,6 +79,22 @@ typing-extensions = ">=3.7.4"
colorama = ["colorama (>=0.4.3)"] colorama = ["colorama (>=0.4.3)"]
d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] d = ["aiohttp (>=3.3.2)", "aiohttp-cors"]
[[package]]
name = "botocore"
version = "1.24.4"
description = "Low-level, data-driven core of boto 3."
category = "main"
optional = false
python-versions = ">= 3.6"
[package.dependencies]
jmespath = ">=0.7.1,<1.0.0"
python-dateutil = ">=2.1,<3.0.0"
urllib3 = ">=1.25.4,<1.27"
[package.extras]
crt = ["awscrt (==0.12.5)"]
[[package]] [[package]]
name = "certifi" name = "certifi"
version = "2021.10.8" version = "2021.10.8"
@ -148,35 +164,54 @@ category = "main"
optional = false optional = false
python-versions = ">=3.6, <3.7" python-versions = ">=3.6, <3.7"
[[package]]
name = "deprecated"
version = "1.2.13"
description = "Python @deprecated decorator to deprecate old python classes, functions or methods."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[package.dependencies]
wrapt = ">=1.10,<2"
[package.extras]
dev = ["tox", "bump2version (<1)", "sphinx (<2)", "importlib-metadata (<3)", "importlib-resources (<4)", "configparser (<5)", "sphinxcontrib-websupport (<2)", "zipp (<2)", "PyTest (<5)", "PyTest-Cov (<2.6)", "pytest", "pytest-cov"]
[[package]] [[package]]
name = "gql" name = "gql"
version = "3.0.0b1" version = "3.0.0"
description = "GraphQL client for Python" description = "GraphQL client for Python"
category = "main" category = "main"
optional = false optional = false
python-versions = "*" python-versions = "*"
[package.dependencies] [package.dependencies]
aiohttp = {version = ">=3.7.1,<3.8.0", optional = true, markers = "extra == \"all\""} aiohttp = {version = ">=3.7.1,<3.9.0", optional = true, markers = "extra == \"all\""}
graphql-core = ">=3.1.5,<3.2" botocore = {version = ">=1.21,<2", optional = true, markers = "extra == \"all\""}
graphql-core = ">=3.2,<3.3"
requests = {version = ">=2.26,<3", optional = true, markers = "extra == \"all\""} requests = {version = ">=2.26,<3", optional = true, markers = "extra == \"all\""}
requests_toolbelt = {version = ">=0.9.1,<1", optional = true, markers = "extra == \"all\""} requests_toolbelt = {version = ">=0.9.1,<1", optional = true, markers = "extra == \"all\""}
urllib3 = {version = ">=1.26", optional = true, markers = "extra == \"all\""} urllib3 = {version = ">=1.26", optional = true, markers = "extra == \"all\""}
websockets = {version = ">=9,<10", optional = true, markers = "extra == \"all\""} websockets = [
{version = ">=9,<10", optional = true, markers = "python_version <= \"3.6\" or python_version <= \"3.6\" and extra == \"all\""},
{version = ">=10,<11", optional = true, markers = "python_version > \"3.6\" or python_version > \"3.6\" and extra == \"all\""},
]
yarl = ">=1.6,<2.0" yarl = ">=1.6,<2.0"
[package.extras] [package.extras]
aiohttp = ["aiohttp (>=3.7.1,<3.8.0)"] aiohttp = ["aiohttp (>=3.7.1,<3.9.0)"]
all = ["aiohttp (>=3.7.1,<3.8.0)", "requests (>=2.26,<3)", "requests_toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)", "websockets (>=9,<10)"] all = ["aiohttp (>=3.7.1,<3.9.0)", "requests (>=2.26,<3)", "requests_toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)", "botocore (>=1.21,<2)", "websockets (>=9,<10)", "websockets (>=10,<11)"]
dev = ["aiohttp (>=3.7.1,<3.8.0)", "requests (>=2.26,<3)", "requests_toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)", "websockets (>=9,<10)", "black (==19.10b0)", "check-manifest (>=0.42,<1)", "flake8 (==3.8.1)", "isort (==4.3.21)", "mypy (==0.770)", "sphinx (>=3.0.0,<4)", "sphinx_rtd_theme (>=0.4,<1)", "sphinx-argparse (==0.2.5)", "parse (==1.15.0)", "pytest (==5.4.2)", "pytest-asyncio (==0.11.0)", "pytest-cov (==2.8.1)", "mock (==4.0.2)", "vcrpy (==4.0.2)", "aiofiles"] botocore = ["botocore (>=1.21,<2)"]
dev = ["aiohttp (>=3.7.1,<3.9.0)", "requests (>=2.26,<3)", "requests_toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)", "botocore (>=1.21,<2)", "black (==19.10b0)", "check-manifest (>=0.42,<1)", "flake8 (==3.8.1)", "isort (==4.3.21)", "mypy (==0.910)", "sphinx (>=3.0.0,<4)", "sphinx_rtd_theme (>=0.4,<1)", "sphinx-argparse (==0.2.5)", "types-aiofiles", "types-mock", "types-requests", "parse (==1.15.0)", "pytest (==6.2.5)", "pytest-asyncio (==0.16.0)", "pytest-cov (==3.0.0)", "mock (==4.0.2)", "vcrpy (==4.0.2)", "aiofiles", "websockets (>=9,<10)", "websockets (>=10,<11)"]
requests = ["requests (>=2.26,<3)", "requests_toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)"] requests = ["requests (>=2.26,<3)", "requests_toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)"]
test = ["aiohttp (>=3.7.1,<3.8.0)", "requests (>=2.26,<3)", "requests_toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)", "websockets (>=9,<10)", "parse (==1.15.0)", "pytest (==5.4.2)", "pytest-asyncio (==0.11.0)", "pytest-cov (==2.8.1)", "mock (==4.0.2)", "vcrpy (==4.0.2)", "aiofiles"] test = ["aiohttp (>=3.7.1,<3.9.0)", "requests (>=2.26,<3)", "requests_toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)", "botocore (>=1.21,<2)", "parse (==1.15.0)", "pytest (==6.2.5)", "pytest-asyncio (==0.16.0)", "pytest-cov (==3.0.0)", "mock (==4.0.2)", "vcrpy (==4.0.2)", "aiofiles", "websockets (>=9,<10)", "websockets (>=10,<11)"]
test_no_transport = ["parse (==1.15.0)", "pytest (==5.4.2)", "pytest-asyncio (==0.11.0)", "pytest-cov (==2.8.1)", "mock (==4.0.2)", "vcrpy (==4.0.2)", "aiofiles"] test_no_transport = ["parse (==1.15.0)", "pytest (==6.2.5)", "pytest-asyncio (==0.16.0)", "pytest-cov (==3.0.0)", "mock (==4.0.2)", "vcrpy (==4.0.2)", "aiofiles"]
websockets = ["websockets (>=9,<10)"] websockets = ["websockets (>=9,<10)", "websockets (>=10,<11)"]
[[package]] [[package]]
name = "graphql-core" name = "graphql-core"
version = "3.1.6" version = "3.2.0"
description = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL." description = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL."
category = "main" category = "main"
optional = false optional = false
@ -240,6 +275,14 @@ requirements_deprecated_finder = ["pipreqs", "pip-api"]
colors = ["colorama (>=0.4.3,<0.5.0)"] colors = ["colorama (>=0.4.3,<0.5.0)"]
plugins = ["setuptools"] plugins = ["setuptools"]
[[package]]
name = "jmespath"
version = "0.10.0"
description = "JSON Matching Expressions"
category = "main"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]] [[package]]
name = "multidict" name = "multidict"
version = "5.2.0" version = "5.2.0"
@ -373,6 +416,17 @@ python-versions = "*"
[package.dependencies] [package.dependencies]
pytest = "*" pytest = "*"
[[package]]
name = "python-dateutil"
version = "2.8.2"
description = "Extensions to the standard Python datetime module"
category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
[package.dependencies]
six = ">=1.5"
[[package]] [[package]]
name = "regex" name = "regex"
version = "2021.11.10" version = "2021.11.10"
@ -410,6 +464,14 @@ python-versions = "*"
[package.dependencies] [package.dependencies]
requests = ">=2.0.1,<3.0.0" requests = ">=2.0.1,<3.0.0"
[[package]]
name = "six"
version = "1.16.0"
description = "Python 2 and 3 compatibility utilities"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.10.2" version = "0.10.2"
@ -471,6 +533,22 @@ category = "main"
optional = false optional = false
python-versions = ">=3.6.1" python-versions = ">=3.6.1"
[[package]]
name = "websockets"
version = "10.2"
description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
category = "main"
optional = false
python-versions = ">=3.7"
[[package]]
name = "wrapt"
version = "1.13.3"
description = "Module for decorators, wrappers and monkey patching."
category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
[[package]] [[package]]
name = "yarl" name = "yarl"
version = "1.7.2" version = "1.7.2"
@ -499,7 +577,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.6.5" python-versions = "^3.6.5"
content-hash = "842f390b7c3b4c3a21d2113dc0aec26707b7698d748cbf1a195b9f4e29f40072" content-hash = "78b3a6fe933735ef4f3c0dca34c08521ab2c11aceb2b7f5572846870d39d46f4"
[metadata.files] [metadata.files]
aiohttp = [ aiohttp = [
@ -560,6 +638,10 @@ attrs = [
black = [ black = [
{file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"},
] ]
botocore = [
{file = "botocore-1.24.4-py3-none-any.whl", hash = "sha256:692fcad31733674c8faffc65da8ddc8ab4839f407ad8470c103e0e7aed9c7556"},
{file = "botocore-1.24.4.tar.gz", hash = "sha256:8e9ae6b718ca318b4aeeee45aa9fad5f52e882a2291d919cfa4b753928223abb"},
]
certifi = [ certifi = [
{file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
{file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"},
@ -633,12 +715,16 @@ dataclasses = [
{file = "dataclasses-0.8-py3-none-any.whl", hash = "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf"}, {file = "dataclasses-0.8-py3-none-any.whl", hash = "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf"},
{file = "dataclasses-0.8.tar.gz", hash = "sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97"}, {file = "dataclasses-0.8.tar.gz", hash = "sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97"},
] ]
deprecated = [
{file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"},
{file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"},
]
gql = [ gql = [
{file = "gql-3.0.0b1.tar.gz", hash = "sha256:a08195e73ed08785e1aef71a540e514f80dbfa711b9effba31ba15fcb687f1fd"}, {file = "gql-3.0.0.tar.gz", hash = "sha256:a21ff880a69caec8786be5cc6de7de6fc2f2b87547af8cd30746b9401ffd47b2"},
] ]
graphql-core = [ graphql-core = [
{file = "graphql-core-3.1.6.tar.gz", hash = "sha256:e65975b6a13878f9113a1fa5320760585b522d139944e005936b1b8358d0651a"}, {file = "graphql-core-3.2.0.tar.gz", hash = "sha256:86e2a0be008bfde19ef78388de8a725a1d942a9190ca431c24a60837973803ce"},
{file = "graphql_core-3.1.6-py3-none-any.whl", hash = "sha256:c78d09596d347e1cffd266c5384abfedf43ed1eae08729773bebb3d527fe5a14"}, {file = "graphql_core-3.2.0-py3-none-any.whl", hash = "sha256:0dda7e63676f119bb3d814621190fedad72fda07a8e9ab780bedd9f1957c6dc6"},
] ]
idna = [ idna = [
{file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
@ -659,6 +745,10 @@ isort = [
{file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
{file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
] ]
jmespath = [
{file = "jmespath-0.10.0-py2.py3-none-any.whl", hash = "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"},
{file = "jmespath-0.10.0.tar.gz", hash = "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9"},
]
multidict = [ multidict = [
{file = "multidict-5.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3822c5894c72e3b35aae9909bef66ec83e44522faf767c0ad39e0e2de11d3b55"}, {file = "multidict-5.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3822c5894c72e3b35aae9909bef66ec83e44522faf767c0ad39e0e2de11d3b55"},
{file = "multidict-5.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:28e6d883acd8674887d7edc896b91751dc2d8e87fbdca8359591a13872799e4e"}, {file = "multidict-5.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:28e6d883acd8674887d7edc896b91751dc2d8e87fbdca8359591a13872799e4e"},
@ -794,6 +884,10 @@ pytest-ordering = [
{file = "pytest_ordering-0.6-py2-none-any.whl", hash = "sha256:27fba3fc265f5d0f8597e7557885662c1bdc1969497cd58aff6ed21c3b617de2"}, {file = "pytest_ordering-0.6-py2-none-any.whl", hash = "sha256:27fba3fc265f5d0f8597e7557885662c1bdc1969497cd58aff6ed21c3b617de2"},
{file = "pytest_ordering-0.6-py3-none-any.whl", hash = "sha256:3f314a178dbeb6777509548727dc69edf22d6d9a2867bf2d310ab85c403380b6"}, {file = "pytest_ordering-0.6-py3-none-any.whl", hash = "sha256:3f314a178dbeb6777509548727dc69edf22d6d9a2867bf2d310ab85c403380b6"},
] ]
python-dateutil = [
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
]
regex = [ regex = [
{file = "regex-2021.11.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9345b6f7ee578bad8e475129ed40123d265464c4cfead6c261fd60fc9de00bcf"}, {file = "regex-2021.11.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9345b6f7ee578bad8e475129ed40123d265464c4cfead6c261fd60fc9de00bcf"},
{file = "regex-2021.11.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:416c5f1a188c91e3eb41e9c8787288e707f7d2ebe66e0a6563af280d9b68478f"}, {file = "regex-2021.11.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:416c5f1a188c91e3eb41e9c8787288e707f7d2ebe66e0a6563af280d9b68478f"},
@ -878,6 +972,10 @@ requests-toolbelt = [
{file = "requests-toolbelt-0.9.1.tar.gz", hash = "sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0"}, {file = "requests-toolbelt-0.9.1.tar.gz", hash = "sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0"},
{file = "requests_toolbelt-0.9.1-py2.py3-none-any.whl", hash = "sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f"}, {file = "requests_toolbelt-0.9.1-py2.py3-none-any.whl", hash = "sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f"},
] ]
six = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
toml = [ toml = [
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
@ -995,6 +1093,107 @@ websockets = [
{file = "websockets-9.1-cp39-cp39-win32.whl", hash = "sha256:be5fd35e99970518547edc906efab29afd392319f020c3c58b0e1a158e16ed20"}, {file = "websockets-9.1-cp39-cp39-win32.whl", hash = "sha256:be5fd35e99970518547edc906efab29afd392319f020c3c58b0e1a158e16ed20"},
{file = "websockets-9.1-cp39-cp39-win_amd64.whl", hash = "sha256:85db8090ba94e22d964498a47fdd933b8875a1add6ebc514c7ac8703eb97bbf0"}, {file = "websockets-9.1-cp39-cp39-win_amd64.whl", hash = "sha256:85db8090ba94e22d964498a47fdd933b8875a1add6ebc514c7ac8703eb97bbf0"},
{file = "websockets-9.1.tar.gz", hash = "sha256:276d2339ebf0df4f45df453923ebd2270b87900eda5dfd4a6b0cfa15f82111c3"}, {file = "websockets-9.1.tar.gz", hash = "sha256:276d2339ebf0df4f45df453923ebd2270b87900eda5dfd4a6b0cfa15f82111c3"},
{file = "websockets-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5396710f86a306cf52f87fd8ea594a0e894ba0cc5a36059eaca3a477dc332aa"},
{file = "websockets-10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b22bdc795e62e71118b63e14a08bacfa4f262fd2877de7e5b950f5ac16b0348f"},
{file = "websockets-10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5b04270b5613f245ec84bb2c6a482a9d009aefad37c0575f6cda8499125d5d5c"},
{file = "websockets-10.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5c335dc0e7dc271ef36df3f439868b3c790775f345338c2f61a562f1074187b"},
{file = "websockets-10.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6a009eb551c46fd79737791c0c833fc0e5b56bcd1c3057498b262d660b92e9cd"},
{file = "websockets-10.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a10c0c1ee02164246f90053273a42d72a3b2452a7e7486fdae781138cf7fbe2d"},
{file = "websockets-10.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7b38a5c9112e3dbbe45540f7b60c5204f49b3cb501b40950d6ab34cd202ab1d0"},
{file = "websockets-10.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2aa9b91347ecd0412683f28aabe27f6bad502d89bd363b76e0a3508b1596402e"},
{file = "websockets-10.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b7fe45ae43ac814beb8ca09d6995b56800676f2cfa8e23f42839dc69bba34a42"},
{file = "websockets-10.2-cp310-cp310-win32.whl", hash = "sha256:cef40a1b183dcf39d23b392e9dd1d9b07ab9c46aadf294fff1350fb79146e72b"},
{file = "websockets-10.2-cp310-cp310-win_amd64.whl", hash = "sha256:c21a67ab9a94bd53e10bba21912556027fea944648a09e6508415ad14e37c325"},
{file = "websockets-10.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb316b87cbe3c0791c2ad92a5a36bf6adc87c457654335810b25048c1daa6fd5"},
{file = "websockets-10.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f14bd10e170abc01682a9f8b28b16e6f20acf6175945ef38db6ffe31b0c72c3f"},
{file = "websockets-10.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fa35c5d1830d0fb7b810324e9eeab9aa92e8f273f11fdbdc0741dcded6d72b9f"},
{file = "websockets-10.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:71a4491cfe7a9f18ee57d41163cb6a8a3fa591e0f0564ca8b0ed86b2a30cced4"},
{file = "websockets-10.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6193bbc1ee63aadeb9a4d81de0e19477401d150d506aee772d8380943f118186"},
{file = "websockets-10.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8beac786a388bb99a66c3be4ab0fb38273c0e3bc17f612a4e0a47c4fc8b9c045"},
{file = "websockets-10.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c67d9cacb3f6537ca21e9b224d4fd08481538e43bcac08b3d93181b0816def39"},
{file = "websockets-10.2-cp37-cp37m-win32.whl", hash = "sha256:a03a25d95cc7400bd4d61a63460b5d85a7761c12075ee2f51de1ffe73aa593d3"},
{file = "websockets-10.2-cp37-cp37m-win_amd64.whl", hash = "sha256:f8296b8408ec6853b26771599990721a26403e62b9de7e50ac0a056772ac0b5e"},
{file = "websockets-10.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7bb9d8a6beca478c7e9bdde0159bd810cc1006ad6a7cb460533bae39da692ca2"},
{file = "websockets-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:05f6e9757017270e7a92a2975e2ae88a9a582ffc4629086fd6039aa80e99cd86"},
{file = "websockets-10.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1c9031e90ebfc486e9cdad532b94004ade3aa39a31d3c46c105bb0b579cd2490"},
{file = "websockets-10.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82bc33db6d8309dc27a3bee11f7da2288ad925fcbabc2a4bb78f7e9c56249baf"},
{file = "websockets-10.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:24b879ba7db12bb525d4e58089fcbe6a3df3ce4666523183654170e86d372cbe"},
{file = "websockets-10.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cf931c33db9c87c53d009856045dd524e4a378445693382a920fa1e0eb77c36c"},
{file = "websockets-10.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:669e54228a4d9457abafed27cbf0e2b9f401445c4dfefc12bf8e4db9751703b8"},
{file = "websockets-10.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:bffc65442dd35c473ca9790a3fa3ba06396102a950794f536783f4b8060af8dd"},
{file = "websockets-10.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d4d110a84b63c5cfdd22485acc97b8b919aefeecd6300c0c9d551e055b9a88ea"},
{file = "websockets-10.2-cp38-cp38-win32.whl", hash = "sha256:117383d0a17a0dda349f7a8790763dde75c1508ff8e4d6e8328b898b7df48397"},
{file = "websockets-10.2-cp38-cp38-win_amd64.whl", hash = "sha256:0b66421f9f13d4df60cd48ab977ed2c2b6c9147ae1a33caf5a9f46294422fda1"},
{file = "websockets-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ac081aa0307f263d63c5ff0727935c736c8dad51ddf2dc9f5d0c4759842aefaa"},
{file = "websockets-10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b4059e2ccbe6587b6dc9a01db5fc49ead9a884faa4076eea96c5ec62cb32f42a"},
{file = "websockets-10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9ca2ca05a4c29179f06cf6727b45dba5d228da62623ec9df4184413d8aae6cb9"},
{file = "websockets-10.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97950c7c844ec6f8d292440953ae18b99e3a6a09885e09d20d5e7ecd9b914cf8"},
{file = "websockets-10.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:98f57b3120f8331cd7440dbe0e776474f5e3632fdaa474af1f6b754955a47d71"},
{file = "websockets-10.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a72b92f96e5e540d5dda99ee3346e199ade8df63152fa3c737260da1730c411f"},
{file = "websockets-10.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:038afef2a05893578d10dadbdbb5f112bd115c46347e1efe99f6a356ff062138"},
{file = "websockets-10.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f09f46b1ff6d09b01c7816c50bd1903cf7d02ebbdb63726132717c2fcda835d5"},
{file = "websockets-10.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2349fa81b6b959484bb2bda556ccb9eb70ba68987646a0f8a537a1a18319fb03"},
{file = "websockets-10.2-cp39-cp39-win32.whl", hash = "sha256:bef03a51f9657fb03d8da6ccd233fe96e04101a852f0ffd35f5b725b28221ff3"},
{file = "websockets-10.2-cp39-cp39-win_amd64.whl", hash = "sha256:1c1f3b18c8162e3b09761d0c6a0305fd642934202541cc511ef972cb9463261e"},
{file = "websockets-10.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5a38a0175ae82e4a8c4bac29fc01b9ee26d7d5a614e5ee11e7813c68a7d938ce"},
{file = "websockets-10.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6e56606842bb24e16e36ae7eb308d866b4249cf0be8f63b212f287eeb76b124"},
{file = "websockets-10.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0f73cb2526d6da268e86977b2c4b58f2195994e53070fe567d5487c6436047e6"},
{file = "websockets-10.2-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0cd02f36d37e503aca88ab23cc0a1a0e92a263d37acf6331521eb38040dcf77b"},
{file = "websockets-10.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:56d48eebe9e39ce0d68701bce3b21df923aa05dcc00f9fd8300de1df31a7c07c"},
{file = "websockets-10.2.tar.gz", hash = "sha256:8351c3c86b08156337b0e4ece0e3c5ec3e01fcd14e8950996832a23c99416098"},
]
wrapt = [
{file = "wrapt-1.13.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:e05e60ff3b2b0342153be4d1b597bbcfd8330890056b9619f4ad6b8d5c96a81a"},
{file = "wrapt-1.13.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:85148f4225287b6a0665eef08a178c15097366d46b210574a658c1ff5b377489"},
{file = "wrapt-1.13.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:2dded5496e8f1592ec27079b28b6ad2a1ef0b9296d270f77b8e4a3a796cf6909"},
{file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e94b7d9deaa4cc7bac9198a58a7240aaf87fe56c6277ee25fa5b3aa1edebd229"},
{file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:498e6217523111d07cd67e87a791f5e9ee769f9241fcf8a379696e25806965af"},
{file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ec7e20258ecc5174029a0f391e1b948bf2906cd64c198a9b8b281b811cbc04de"},
{file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:87883690cae293541e08ba2da22cacaae0a092e0ed56bbba8d018cc486fbafbb"},
{file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:f99c0489258086308aad4ae57da9e8ecf9e1f3f30fa35d5e170b4d4896554d80"},
{file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6a03d9917aee887690aa3f1747ce634e610f6db6f6b332b35c2dd89412912bca"},
{file = "wrapt-1.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:936503cb0a6ed28dbfa87e8fcd0a56458822144e9d11a49ccee6d9a8adb2ac44"},
{file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f9c51d9af9abb899bd34ace878fbec8bf357b3194a10c4e8e0a25512826ef056"},
{file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:220a869982ea9023e163ba915077816ca439489de6d2c09089b219f4e11b6785"},
{file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0877fe981fd76b183711d767500e6b3111378ed2043c145e21816ee589d91096"},
{file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:43e69ffe47e3609a6aec0fe723001c60c65305784d964f5007d5b4fb1bc6bf33"},
{file = "wrapt-1.13.3-cp310-cp310-win32.whl", hash = "sha256:78dea98c81915bbf510eb6a3c9c24915e4660302937b9ae05a0947164248020f"},
{file = "wrapt-1.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:ea3e746e29d4000cd98d572f3ee2a6050a4f784bb536f4ac1f035987fc1ed83e"},
{file = "wrapt-1.13.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8c73c1a2ec7c98d7eaded149f6d225a692caa1bd7b2401a14125446e9e90410d"},
{file = "wrapt-1.13.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:086218a72ec7d986a3eddb7707c8c4526d677c7b35e355875a0fe2918b059179"},
{file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:e92d0d4fa68ea0c02d39f1e2f9cb5bc4b4a71e8c442207433d8db47ee79d7aa3"},
{file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:d4a5f6146cfa5c7ba0134249665acd322a70d1ea61732723c7d3e8cc0fa80755"},
{file = "wrapt-1.13.3-cp35-cp35m-win32.whl", hash = "sha256:8aab36778fa9bba1a8f06a4919556f9f8c7b33102bd71b3ab307bb3fecb21851"},
{file = "wrapt-1.13.3-cp35-cp35m-win_amd64.whl", hash = "sha256:944b180f61f5e36c0634d3202ba8509b986b5fbaf57db3e94df11abee244ba13"},
{file = "wrapt-1.13.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2ebdde19cd3c8cdf8df3fc165bc7827334bc4e353465048b36f7deeae8ee0918"},
{file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:610f5f83dd1e0ad40254c306f4764fcdc846641f120c3cf424ff57a19d5f7ade"},
{file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5601f44a0f38fed36cc07db004f0eedeaadbdcec90e4e90509480e7e6060a5bc"},
{file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:e6906d6f48437dfd80464f7d7af1740eadc572b9f7a4301e7dd3d65db285cacf"},
{file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:766b32c762e07e26f50d8a3468e3b4228b3736c805018e4b0ec8cc01ecd88125"},
{file = "wrapt-1.13.3-cp36-cp36m-win32.whl", hash = "sha256:5f223101f21cfd41deec8ce3889dc59f88a59b409db028c469c9b20cfeefbe36"},
{file = "wrapt-1.13.3-cp36-cp36m-win_amd64.whl", hash = "sha256:f122ccd12fdc69628786d0c947bdd9cb2733be8f800d88b5a37c57f1f1d73c10"},
{file = "wrapt-1.13.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:46f7f3af321a573fc0c3586612db4decb7eb37172af1bc6173d81f5b66c2e068"},
{file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:778fd096ee96890c10ce96187c76b3e99b2da44e08c9e24d5652f356873f6709"},
{file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0cb23d36ed03bf46b894cfec777eec754146d68429c30431c99ef28482b5c1df"},
{file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:96b81ae75591a795d8c90edc0bfaab44d3d41ffc1aae4d994c5aa21d9b8e19a2"},
{file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7dd215e4e8514004c8d810a73e342c536547038fb130205ec4bba9f5de35d45b"},
{file = "wrapt-1.13.3-cp37-cp37m-win32.whl", hash = "sha256:47f0a183743e7f71f29e4e21574ad3fa95676136f45b91afcf83f6a050914829"},
{file = "wrapt-1.13.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fd76c47f20984b43d93de9a82011bb6e5f8325df6c9ed4d8310029a55fa361ea"},
{file = "wrapt-1.13.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b73d4b78807bd299b38e4598b8e7bd34ed55d480160d2e7fdaabd9931afa65f9"},
{file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ec9465dd69d5657b5d2fa6133b3e1e989ae27d29471a672416fd729b429eb554"},
{file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dd91006848eb55af2159375134d724032a2d1d13bcc6f81cd8d3ed9f2b8e846c"},
{file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ae9de71eb60940e58207f8e71fe113c639da42adb02fb2bcbcaccc1ccecd092b"},
{file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:51799ca950cfee9396a87f4a1240622ac38973b6df5ef7a41e7f0b98797099ce"},
{file = "wrapt-1.13.3-cp38-cp38-win32.whl", hash = "sha256:4b9c458732450ec42578b5642ac53e312092acf8c0bfce140ada5ca1ac556f79"},
{file = "wrapt-1.13.3-cp38-cp38-win_amd64.whl", hash = "sha256:7dde79d007cd6dfa65afe404766057c2409316135cb892be4b1c768e3f3a11cb"},
{file = "wrapt-1.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:981da26722bebb9247a0601e2922cedf8bb7a600e89c852d063313102de6f2cb"},
{file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:705e2af1f7be4707e49ced9153f8d72131090e52be9278b5dbb1498c749a1e32"},
{file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:25b1b1d5df495d82be1c9d2fad408f7ce5ca8a38085e2da41bb63c914baadff7"},
{file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:77416e6b17926d953b5c666a3cb718d5945df63ecf922af0ee576206d7033b5e"},
{file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:865c0b50003616f05858b22174c40ffc27a38e67359fa1495605f96125f76640"},
{file = "wrapt-1.13.3-cp39-cp39-win32.whl", hash = "sha256:0a017a667d1f7411816e4bf214646d0ad5b1da2c1ea13dec6c162736ff25a374"},
{file = "wrapt-1.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:81bd7c90d28a4b2e1df135bfbd7c23aee3050078ca6441bead44c42483f9ebfb"},
{file = "wrapt-1.13.3.tar.gz", hash = "sha256:1fea9cd438686e6682271d36f3481a9f3636195578bab9ca3382e2f5f01fc185"},
] ]
yarl = [ yarl = [
{file = "yarl-1.7.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f2a8508f7350512434e41065684076f640ecce176d262a7d54f0da41d99c5a95"}, {file = "yarl-1.7.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f2a8508f7350512434e41065684076f640ecce176d262a7d54f0da41d99c5a95"},

Просмотреть файл

@ -16,6 +16,7 @@ pydantic = "^1.8.2"
appdirs = "^1.4.4" appdirs = "^1.4.4"
gql = {version = ">=3.0.0b1", extras = ["all"], allow-prereleases = true} gql = {version = ">=3.0.0b1", extras = ["all"], allow-prereleases = true}
ujson = "^4.3.0" ujson = "^4.3.0"
Deprecated = "^1.2.13"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
black = "^20.8b1" black = "^20.8b1"

Просмотреть файл

@ -1,5 +1,7 @@
import re import re
from warnings import warn from warnings import warn
from deprecated import deprecated
from specklepy.api.credentials import Account, get_account_from_token
from specklepy.logging.exceptions import ( from specklepy.logging.exceptions import (
GraphQLException, GraphQLException,
SpeckleException, SpeckleException,
@ -39,9 +41,9 @@ class SpeckleClient:
client = SpeckleClient(host="speckle.xyz") # or whatever your host is client = SpeckleClient(host="speckle.xyz") # or whatever your host is
# client = SpeckleClient(host="localhost:3000", use_ssl=False) or use local server # client = SpeckleClient(host="localhost:3000", use_ssl=False) or use local server
# authenticate the client with a token (account has been added in Speckle Manager) # authenticate the client with an account (account has been added in Speckle Manager)
account = get_default_account() account = get_default_account()
client.authenticate(token=account.token) client.authenticate_with_account(account)
# create a new stream. this returns the stream id # create a new stream. this returns the stream id
new_stream_id = client.stream.create(name="a shiny new stream") new_stream_id = client.stream.create(name="a shiny new stream")
@ -66,9 +68,9 @@ class SpeckleClient:
host = re.sub(r"((^\w+:|^)\/\/)|(\/$)", "", host) host = re.sub(r"((^\w+:|^)\/\/)|(\/$)", "", host)
self.url = f"{http_protocol}://{host}" self.url = f"{http_protocol}://{host}"
self.graphql = self.url + "/graphql" self.graphql = f"{self.url}/graphql"
self.ws_url = f"{ws_protocol}://{host}/graphql" self.ws_url = f"{ws_protocol}://{host}/graphql"
self.me = None self.account = Account()
self.httpclient = Client( self.httpclient = Client(
transport=RequestsHTTPTransport(url=self.graphql, verify=True, retries=3) transport=RequestsHTTPTransport(url=self.graphql, verify=True, retries=3)
@ -88,10 +90,12 @@ class SpeckleClient:
raise SpeckleException(f"{self.url} is not a compatible Speckle Server", ex) raise SpeckleException(f"{self.url} is not a compatible Speckle Server", ex)
def __repr__(self): def __repr__(self):
return ( return f"SpeckleClient( server: {self.url}, authenticated: {self.account.token is not None} )"
f"SpeckleClient( server: {self.url}, authenticated: {self.me is not None} )"
)
@deprecated(
version="2.6.0",
reason="Renamed: please use `authenticate_with_account` or `authenticate_with_token` instead.",
)
def authenticate(self, token: str) -> None: def authenticate(self, token: str) -> None:
"""Authenticate the client using a personal access token """Authenticate the client using a personal access token
The token is saved in the client object and a synchronous GraphQL entrypoint is created The token is saved in the client object and a synchronous GraphQL entrypoint is created
@ -99,9 +103,31 @@ class SpeckleClient:
Arguments: Arguments:
token {str} -- an api token token {str} -- an api token
""" """
self.me = {"token": token} self.authenticate_with_token(token)
self._set_up_client()
def authenticate_with_token(self, token: str) -> None:
"""Authenticate the client using a personal access token
The token is saved in the client object and a synchronous GraphQL entrypoint is created
Arguments:
token {str} -- an api token
"""
self.account = get_account_from_token(token, self.url)
self._set_up_client()
def authenticate_with_account(self, account: Account) -> None:
"""Authenticate the client using an Account object
The account is saved in the client object and a synchronous GraphQL entrypoint is created
Arguments:
account {Account} -- the account object which can be found with `get_default_account` or `get_local_accounts`
"""
self.account = account
def _set_up_client(self) -> None:
headers = { headers = {
"Authorization": f"Bearer {self.me['token']}", "Authorization": f"Bearer {self.account.token}",
"Content-Type": "application/json", "Content-Type": "application/json",
} }
httptransport = RequestsHTTPTransport( httptransport = RequestsHTTPTransport(
@ -109,7 +135,7 @@ class SpeckleClient:
) )
wstransport = WebsocketsTransport( wstransport = WebsocketsTransport(
url=self.ws_url, url=self.ws_url,
init_payload={"Authorization": f"Bearer {self.me['token']}"}, init_payload={"Authorization": f"Bearer {self.account.token}"},
) )
self.httpclient = Client(transport=httptransport) self.httpclient = Client(transport=httptransport)
self.wsclient = Client(transport=wstransport) self.wsclient = Client(transport=wstransport)
@ -119,7 +145,7 @@ class SpeckleClient:
if isinstance(self.user.get(), GraphQLException): if isinstance(self.user.get(), GraphQLException):
warn( warn(
SpeckleWarning( SpeckleWarning(
f"Invalid token - could not authenticate Speckle Client for server {self.url}" f"Possibly invalid token - could not authenticate Speckle Client for server {self.url}"
) )
) )
@ -128,23 +154,25 @@ class SpeckleClient:
def _init_resources(self) -> None: def _init_resources(self) -> None:
self.stream = stream.Resource( self.stream = stream.Resource(
me=self.me, basepath=self.url, client=self.httpclient account=self.account, basepath=self.url, client=self.httpclient
) )
self.commit = commit.Resource( self.commit = commit.Resource(
me=self.me, basepath=self.url, client=self.httpclient account=self.account, basepath=self.url, client=self.httpclient
) )
self.branch = branch.Resource( self.branch = branch.Resource(
me=self.me, basepath=self.url, client=self.httpclient account=self.account, basepath=self.url, client=self.httpclient
) )
self.object = object.Resource( self.object = object.Resource(
me=self.me, basepath=self.url, client=self.httpclient account=self.account, basepath=self.url, client=self.httpclient
) )
self.server = server.Resource( self.server = server.Resource(
me=self.me, basepath=self.url, client=self.httpclient account=self.account, basepath=self.url, client=self.httpclient
)
self.user = user.Resource(
account=self.account, basepath=self.url, client=self.httpclient
) )
self.user = user.Resource(me=self.me, basepath=self.url, client=self.httpclient)
self.subscribe = subscriptions.Resource( self.subscribe = subscriptions.Resource(
me=self.me, account=self.account,
basepath=self.ws_url, basepath=self.ws_url,
client=self.wsclient, client=self.wsclient,
) )
@ -152,7 +180,9 @@ class SpeckleClient:
def __getattr__(self, name): def __getattr__(self, name):
try: try:
attr = getattr(resources, name) attr = getattr(resources, name)
return attr.Resource(me=self.me, basepath=self.url, client=self.httpclient) return attr.Resource(
account=self.account, basepath=self.url, client=self.httpclient
)
except: except:
raise SpeckleException( raise SpeckleException(
f"Method {name} is not supported by the SpeckleClient class" f"Method {name} is not supported by the SpeckleClient class"

Просмотреть файл

@ -1,29 +1,25 @@
import os import os
from warnings import warn from pydantic import BaseModel, Field
from pydantic import BaseModel
from typing import List, Optional from typing import List, Optional
from urllib.parse import urlparse, unquote
from specklepy.logging import metrics from specklepy.logging import metrics
from specklepy.api.models import ServerInfo from specklepy.api.models import ServerInfo
from specklepy.api.client import SpeckleClient
from specklepy.transports.sqlite import SQLiteTransport from specklepy.transports.sqlite import SQLiteTransport
from specklepy.transports.server.server import ServerTransport from specklepy.logging.exceptions import SpeckleException
from specklepy.logging.exceptions import SpeckleException, SpeckleWarning
class UserInfo(BaseModel): class UserInfo(BaseModel):
name: str name: Optional[str]
email: str email: Optional[str]
company: Optional[str] company: Optional[str]
id: str id: Optional[str]
class Account(BaseModel): class Account(BaseModel):
isDefault: bool = None isDefault: bool = False
token: str token: str = None
refreshToken: str = None refreshToken: str = None
serverInfo: ServerInfo serverInfo: ServerInfo = Field(default_factory=ServerInfo)
userInfo: UserInfo userInfo: UserInfo = Field(default_factory=UserInfo)
id: str = None id: str = None
def __repr__(self) -> str: def __repr__(self) -> str:
@ -32,6 +28,12 @@ class Account(BaseModel):
def __str__(self) -> str: def __str__(self) -> str:
return self.__repr__() return self.__repr__()
@classmethod
def from_token(cls, token: str, server_url: str = None):
acct = cls(token=token)
acct.serverInfo.url = server_url
return acct
def get_local_accounts(base_path: str = None) -> List[Account]: def get_local_accounts(base_path: str = None) -> List[Account]:
"""Gets all the accounts present in this environment """Gets all the accounts present in this environment
@ -42,7 +44,6 @@ def get_local_accounts(base_path: str = None) -> List[Account]:
Returns: Returns:
List[Account] -- list of all local accounts or an empty list if no accounts were found List[Account] -- list of all local accounts or an empty list if no accounts were found
""" """
metrics.track(metrics.ACCOUNT_LIST)
account_storage = SQLiteTransport(scope="Accounts", base_path=base_path) account_storage = SQLiteTransport(scope="Accounts", base_path=base_path)
json_path = os.path.join(account_storage._base_path, "Accounts") json_path = os.path.join(account_storage._base_path, "Accounts")
os.makedirs(json_path, exist_ok=True) os.makedirs(json_path, exist_ok=True)
@ -63,6 +64,13 @@ def get_local_accounts(base_path: str = None) -> List[Account]:
"Invalid json accounts could not be read. Please fix or remove them.", "Invalid json accounts could not be read. Please fix or remove them.",
ex, ex,
) )
metrics.track(
metrics.ACCOUNTS,
next(
(acc for acc in accounts if acc.isDefault),
accounts[0] if accounts else None,
),
)
return accounts return accounts
@ -75,7 +83,6 @@ def get_default_account(base_path: str = None) -> Account:
Returns: Returns:
Account -- the default account or None if no local accounts were found Account -- the default account or None if no local accounts were found
""" """
metrics.track(metrics.ACCOUNT_DEFAULT)
accounts = get_local_accounts(base_path=base_path) accounts = get_local_accounts(base_path=base_path)
if not accounts: if not accounts:
return None return None
@ -84,147 +91,41 @@ def get_default_account(base_path: str = None) -> Account:
if not default: if not default:
default = accounts[0] default = accounts[0]
default.isDefault = True default.isDefault = True
metrics.initialise_tracker(default)
return default return default
class StreamWrapper: def get_account_from_token(token: str, server_url: str = None) -> Account:
"""Gets the local account for the token if it exists
Arguments:
token {str} -- the api token
Returns:
Account -- the local account with this token or a shell account containing just the token and url if no local account is found
""" """
The `StreamWrapper` gives you some handy helpers to deal with urls and get authenticated clients and transports. accounts = get_local_accounts()
if not accounts:
return Account.from_token(token, server_url)
Construct a `StreamWrapper` with a stream, branch, commit, or object URL. The corresponding ids will be stored acct = next((acc for acc in accounts if acc.token == token), None)
in the wrapper. If you have local accounts on the machine, you can use the `get_account` and `get_client` methods if acct:
to get a local account for the server. You can also pass a token into `get_client` if you don't have a corresponding return acct
local account for the server.
```py if server_url:
from specklepy.api.credentials import StreamWrapper url = server_url.lower()
acct = next(
# provide any stream, branch, commit, object, or globals url (acc for acc in accounts if url in acc.serverInfo.url.lower()), None
wrapper = StreamWrapper("https://speckle.xyz/streams/3073b96e86/commits/604bea8cc6")
# get an authenticated SpeckleClient if you have a local account for the server
client = wrapper.get_client()
# get an authenticated ServerTransport if you have a local account for the server
transport = wrapper.get_transport()
```
"""
stream_url: str = None
use_ssl: bool = True
host: str = None
stream_id: str = None
commit_id: str = None
object_id: str = None
branch_name: str = None
_client: SpeckleClient = None
_account: Account = None
def __repr__(self):
return f"StreamWrapper( server: {self.host}, stream_id: {self.stream_id}, type: {self.type} )"
def __str__(self) -> str:
return self.__repr__()
@property
def type(self) -> str:
if self.object_id:
return "object"
elif self.commit_id:
return "commit"
elif self.branch_name:
return "branch"
else:
return "stream" if self.stream_id else "invalid"
def __init__(self, url: str) -> None:
metrics.track("streamwrapper")
self.stream_url = url
parsed = urlparse(url)
self.host = parsed.netloc
self.use_ssl = parsed.scheme == "https"
segments = parsed.path.strip("/").split("/", 3)
if not segments or len(segments) < 2:
raise SpeckleException(
f"Cannot parse {url} into a stream wrapper class - invalid URL provided."
)
while segments:
segment = segments.pop(0)
if segments and segment.lower() == "streams":
self.stream_id = segments.pop(0)
elif segments and segment.lower() == "commits":
self.commit_id = segments.pop(0)
elif segments and segment.lower() == "branches":
self.branch_name = unquote(segments.pop(0))
elif segments and segment.lower() == "objects":
self.object_id = segments.pop(0)
elif segment.lower() == "globals":
self.branch_name = "globals"
if segments:
self.commit_id = segments.pop(0)
else:
raise SpeckleException(
f"Cannot parse {url} into a stream wrapper class - invalid URL provided."
)
if not self.stream_id:
raise SpeckleException(
f"Cannot parse {url} into a stream wrapper class - no stream id found."
)
def get_account(self) -> Account:
"""
Gets an account object for this server from the local accounts db (added via Speckle Manager or a json file)
"""
if self._account:
return self._account
self._account = next(
(a for a in get_local_accounts() if self.host in a.serverInfo.url),
None,
) )
if acct:
return acct
return self._account return Account.from_token(token, server_url)
def get_client(self, token: str = None) -> SpeckleClient:
"""
Gets an authenticated client for this server. You may provide a token if there aren't any local accounts on this
machine. If no account is found and no token is provided, an unauthenticated client is returned.
Arguments: class StreamWrapper:
token {str} -- optional token if no local account is available (defaults to None) def __init__(self, url: str = None) -> None:
raise SpeckleException(
Returns: message="The StreamWrapper has moved as of v2.6.0! Please import from specklepy.api.wrapper",
SpeckleClient -- authenticated with a corresponding local account or the provided token exception=DeprecationWarning,
""" )
if self._client and token is None:
return self._client
if not self._account:
self.get_account()
if not self._client:
self._client = SpeckleClient(host=self.host, use_ssl=self.use_ssl)
if self._account is None and token is None:
warn(f"No local account found for server {self.host}", SpeckleWarning)
return self._client
self._client.authenticate(self._account.token if self._account else token)
return self._client
def get_transport(self, token: str = None) -> ServerTransport:
"""
Gets a server transport for this stream using an authenticated client. If there is no local account for this
server and the client was not authenticated with a token, this will throw an exception.
Returns:
ServerTransport -- constructed for this stream with a pre-authenticated client
"""
if not self._client or not self._client.me:
self.get_client(token)
return ServerTransport(self.stream_id, self._client)

Просмотреть файл

@ -2,6 +2,7 @@ from typing import List
from specklepy.logging import metrics from specklepy.logging import metrics
from specklepy.objects.base import Base from specklepy.objects.base import Base
from specklepy.transports.sqlite import SQLiteTransport from specklepy.transports.sqlite import SQLiteTransport
from specklepy.transports.server import ServerTransport
from specklepy.logging.exceptions import SpeckleException from specklepy.logging.exceptions import SpeckleException
from specklepy.transports.abstract_transport import AbstractTransport from specklepy.transports.abstract_transport import AbstractTransport
from specklepy.serialization.base_object_serializer import BaseObjectSerializer from specklepy.serialization.base_object_serializer import BaseObjectSerializer
@ -22,14 +23,18 @@ def send(
Returns: Returns:
str -- the object id of the sent object str -- the object id of the sent object
""" """
metrics.track(metrics.SEND)
if not transports and not use_default_cache: if not transports and not use_default_cache:
raise SpeckleException( raise SpeckleException(
message="You need to provide at least one transport: cannot send with an empty transport list and no default cache" message="You need to provide at least one transport: cannot send with an empty transport list and no default cache"
) )
if transports is None: if transports is None:
metrics.track(metrics.SEND)
transports = [] transports = []
else:
metrics.track(metrics.SEND, getattr(transports[0], "account", None))
if use_default_cache: if use_default_cache:
transports.insert(0, SQLiteTransport()) transports.insert(0, SQLiteTransport())
@ -61,7 +66,7 @@ def receive(
Returns: Returns:
Base -- the base object Base -- the base object
""" """
metrics.track(metrics.RECEIVE) metrics.track(metrics.RECEIVE, getattr(remote_transport, "account", None))
if not local_transport: if not local_transport:
local_transport = SQLiteTransport() local_transport = SQLiteTransport()

Просмотреть файл

@ -1,3 +1,4 @@
from specklepy.api.credentials import Account
from specklepy.transports.sqlite import SQLiteTransport from specklepy.transports.sqlite import SQLiteTransport
from typing import Dict, List from typing import Dict, List
from gql.client import Client from gql.client import Client
@ -10,13 +11,13 @@ from specklepy.serialization.base_object_serializer import BaseObjectSerializer
class ResourceBase(object): class ResourceBase(object):
def __init__( def __init__(
self, self,
me: Dict, account: Account,
basepath: str, basepath: str,
client: Client, client: Client,
name: str, name: str,
methods: list, methods: list,
) -> None: ) -> None:
self.me = me self.account = account
self.basepath = basepath self.basepath = basepath
self.client = client self.client = client
self.name = name self.name = name

Просмотреть файл

@ -1,6 +1,7 @@
from gql import gql from gql import gql
from specklepy.api.resource import ResourceBase from specklepy.api.resource import ResourceBase
from specklepy.api.models import Branch from specklepy.api.models import Branch
from specklepy.logging import metrics
NAME = "branch" NAME = "branch"
METHODS = ["create"] METHODS = ["create"]
@ -9,9 +10,13 @@ METHODS = ["create"]
class Resource(ResourceBase): class Resource(ResourceBase):
"""API Access class for branches""" """API Access class for branches"""
def __init__(self, me, basepath, client) -> None: def __init__(self, account, basepath, client) -> None:
super().__init__( super().__init__(
me=me, basepath=basepath, client=client, name=NAME, methods=METHODS account=account,
basepath=basepath,
client=client,
name=NAME,
methods=METHODS,
) )
self.schema = Branch self.schema = Branch
@ -27,7 +32,7 @@ class Resource(ResourceBase):
Returns: Returns:
id {str} -- the newly created branch's id id {str} -- the newly created branch's id
""" """
metrics.track(metrics.BRANCH, self.account, {"name": "create"})
query = gql( query = gql(
""" """
mutation BranchCreate($branch: BranchCreateInput!) { mutation BranchCreate($branch: BranchCreateInput!) {
@ -58,7 +63,7 @@ class Resource(ResourceBase):
Returns: Returns:
Branch -- the fetched branch with its latest commits Branch -- the fetched branch with its latest commits
""" """
metrics.track(metrics.BRANCH, self.account, {"name": "get"})
query = gql( query = gql(
""" """
query BranchGet($stream_id: String!, $name: String!, $commits_limit: Int!) { query BranchGet($stream_id: String!, $name: String!, $commits_limit: Int!) {
@ -106,6 +111,7 @@ class Resource(ResourceBase):
Returns: Returns:
List[Branch] -- the branches on the stream List[Branch] -- the branches on the stream
""" """
metrics.track(metrics.BRANCH, self.account, {"name": "get"})
query = gql( query = gql(
""" """
query BranchesGet($stream_id: String!, $branches_limit: Int!, $commits_limit: Int!) { query BranchesGet($stream_id: String!, $branches_limit: Int!, $commits_limit: Int!) {
@ -160,6 +166,7 @@ class Resource(ResourceBase):
Returns: Returns:
bool -- True if update is successfull bool -- True if update is successfull
""" """
metrics.track(metrics.BRANCH, self.account, {"name": "update"})
query = gql( query = gql(
""" """
mutation BranchUpdate($branch: BranchUpdateInput!) { mutation BranchUpdate($branch: BranchUpdateInput!) {
@ -193,7 +200,7 @@ class Resource(ResourceBase):
Returns: Returns:
bool -- True if deletion is successful bool -- True if deletion is successful
""" """
metrics.track(metrics.BRANCH, self.account, {"name": "delete"})
query = gql( query = gql(
""" """
mutation BranchDelete($branch: BranchDeleteInput!) { mutation BranchDelete($branch: BranchDeleteInput!) {

Просмотреть файл

@ -2,6 +2,7 @@ from typing import Optional, List
from gql import gql from gql import gql
from specklepy.api.resource import ResourceBase from specklepy.api.resource import ResourceBase
from specklepy.api.models import Commit from specklepy.api.models import Commit
from specklepy.logging import metrics
NAME = "commit" NAME = "commit"
@ -11,9 +12,13 @@ METHODS = []
class Resource(ResourceBase): class Resource(ResourceBase):
"""API Access class for commits""" """API Access class for commits"""
def __init__(self, me, basepath, client) -> None: def __init__(self, account, basepath, client) -> None:
super().__init__( super().__init__(
me=me, basepath=basepath, client=client, name=NAME, methods=METHODS account=account,
basepath=basepath,
client=client,
name=NAME,
methods=METHODS,
) )
self.schema = Commit self.schema = Commit
@ -66,6 +71,7 @@ class Resource(ResourceBase):
Returns: Returns:
List[Commit] -- a list of the most recent commit objects List[Commit] -- a list of the most recent commit objects
""" """
metrics.track(metrics.COMMIT, self.account, {"name": "get"})
query = gql( query = gql(
""" """
query Commits($stream_id: String!, $limit: Int!) { query Commits($stream_id: String!, $limit: Int!) {
@ -119,6 +125,7 @@ class Resource(ResourceBase):
Returns: Returns:
str -- the id of the created commit str -- the id of the created commit
""" """
metrics.track(metrics.COMMIT, self.account, {"name": "create"})
query = gql( query = gql(
""" """
mutation CommitCreate ($commit: CommitCreateInput!){ commitCreate(commit: $commit)} mutation CommitCreate ($commit: CommitCreateInput!){ commitCreate(commit: $commit)}
@ -152,6 +159,7 @@ class Resource(ResourceBase):
Returns: Returns:
bool -- True if the operation succeeded bool -- True if the operation succeeded
""" """
metrics.track(metrics.COMMIT, self.account, {"name": "update"})
query = gql( query = gql(
""" """
mutation CommitUpdate($commit: CommitUpdateInput!){ commitUpdate(commit: $commit)} mutation CommitUpdate($commit: CommitUpdateInput!){ commitUpdate(commit: $commit)}
@ -176,6 +184,7 @@ class Resource(ResourceBase):
Returns: Returns:
bool -- True if the operation succeeded bool -- True if the operation succeeded
""" """
metrics.track(metrics.COMMIT, self.account, {"name": "delete"})
query = gql( query = gql(
""" """
mutation CommitDelete($commit: CommitDeleteInput!){ commitDelete(commit: $commit)} mutation CommitDelete($commit: CommitDeleteInput!){ commitDelete(commit: $commit)}
@ -197,6 +206,7 @@ class Resource(ResourceBase):
""" """
Mark a commit object a received by the source application. Mark a commit object a received by the source application.
""" """
metrics.track(metrics.COMMIT, self.account, {"name": "received"})
query = gql( query = gql(
""" """
mutation CommitReceive($receivedInput:CommitReceivedInput!){ mutation CommitReceive($receivedInput:CommitReceivedInput!){

Просмотреть файл

@ -10,9 +10,13 @@ METHODS = []
class Resource(ResourceBase): class Resource(ResourceBase):
"""API Access class for objects""" """API Access class for objects"""
def __init__(self, me, basepath, client) -> None: def __init__(self, account, basepath, client) -> None:
super().__init__( super().__init__(
me=me, basepath=basepath, client=client, name=NAME, methods=METHODS account=account,
basepath=basepath,
client=client,
name=NAME,
methods=METHODS,
) )
self.schema = Base self.schema = Base

Просмотреть файл

@ -11,9 +11,13 @@ METHODS = ["get", "apps"]
class Resource(ResourceBase): class Resource(ResourceBase):
"""API Access class for the server""" """API Access class for the server"""
def __init__(self, me, basepath, client) -> None: def __init__(self, account, basepath, client) -> None:
super().__init__( super().__init__(
me=me, basepath=basepath, client=client, name=NAME, methods=METHODS account=account,
basepath=basepath,
client=client,
name=NAME,
methods=METHODS,
) )
def get(self) -> ServerInfo: def get(self) -> ServerInfo:

Просмотреть файл

@ -19,9 +19,13 @@ METHODS = [
class Resource(ResourceBase): class Resource(ResourceBase):
"""API Access class for streams""" """API Access class for streams"""
def __init__(self, me, basepath, client) -> None: def __init__(self, account, basepath, client) -> None:
super().__init__( super().__init__(
me=me, basepath=basepath, client=client, name=NAME, methods=METHODS account=account,
basepath=basepath,
client=client,
name=NAME,
methods=METHODS,
) )
self.schema = Stream self.schema = Stream
@ -37,7 +41,7 @@ class Resource(ResourceBase):
Returns: Returns:
Stream -- the retrieved stream Stream -- the retrieved stream
""" """
metrics.track(metrics.STREAM_GET) metrics.track(metrics.STREAM, self.account, {"name": "get"})
query = gql( query = gql(
""" """
query Stream($id: String!, $branch_limit: Int!, $commit_limit: Int!) { query Stream($id: String!, $branch_limit: Int!, $commit_limit: Int!) {
@ -93,7 +97,7 @@ class Resource(ResourceBase):
Returns: Returns:
List[Stream] -- A list of Stream objects List[Stream] -- A list of Stream objects
""" """
metrics.track(metrics.STREAM_LIST) metrics.track(metrics.STREAM, self.account, {"name": "get"})
query = gql( query = gql(
""" """
query User($stream_limit: Int!) { query User($stream_limit: Int!) {
@ -151,7 +155,7 @@ class Resource(ResourceBase):
Returns: Returns:
id {str} -- the id of the newly created stream id {str} -- the id of the newly created stream
""" """
metrics.track(metrics.STREAM_CREATE) metrics.track(metrics.STREAM, self.account, {"name": "create"})
query = gql( query = gql(
""" """
mutation StreamCreate($stream: StreamCreateInput!) { mutation StreamCreate($stream: StreamCreateInput!) {
@ -182,7 +186,7 @@ class Resource(ResourceBase):
Returns: Returns:
bool -- whether the stream update was successful bool -- whether the stream update was successful
""" """
metrics.track(metrics.STREAM_UPDATE) metrics.track(metrics.STREAM, self.account, {"name": "update"})
query = gql( query = gql(
""" """
mutation StreamUpdate($stream: StreamUpdateInput!) { mutation StreamUpdate($stream: StreamUpdateInput!) {
@ -213,7 +217,7 @@ class Resource(ResourceBase):
Returns: Returns:
bool -- whether the deletion was successful bool -- whether the deletion was successful
""" """
metrics.track(metrics.STREAM_DELETE) metrics.track(metrics.STREAM, self.account, {"name": "delete"})
query = gql( query = gql(
""" """
mutation StreamDelete($id: String!) { mutation StreamDelete($id: String!) {
@ -246,7 +250,7 @@ class Resource(ResourceBase):
Returns: Returns:
List[Stream] -- a list of Streams that match the search query List[Stream] -- a list of Streams that match the search query
""" """
metrics.track(metrics.STREAM_SEARCH) metrics.track(metrics.STREAM, self.account, {"name": "search"})
query = gql( query = gql(
""" """
query StreamSearch($search_query: String!,$limit: Int!, $branch_limit:Int!, $commit_limit:Int!) { query StreamSearch($search_query: String!,$limit: Int!, $branch_limit:Int!, $commit_limit:Int!) {
@ -313,6 +317,7 @@ class Resource(ResourceBase):
Returns: Returns:
bool -- True if the operation was successful bool -- True if the operation was successful
""" """
metrics.track(metrics.PERMISSION, self.account, {"name": "add", "role": role})
query = gql( query = gql(
""" """
mutation StreamGrantPermission($permission_params: StreamGrantPermissionInput !) { mutation StreamGrantPermission($permission_params: StreamGrantPermissionInput !) {
@ -346,6 +351,7 @@ class Resource(ResourceBase):
Returns: Returns:
bool -- True if the operation was successful bool -- True if the operation was successful
""" """
metrics.track(metrics.PERMISSION, self.account, {"name": "revoke"})
query = gql( query = gql(
""" """
mutation StreamRevokePermission($permission_params: StreamRevokePermissionInput !) { mutation StreamRevokePermission($permission_params: StreamRevokePermissionInput !) {

Просмотреть файл

@ -29,9 +29,13 @@ def check_wsclient(function):
class Resource(ResourceBase): class Resource(ResourceBase):
"""API Access class for subscriptions""" """API Access class for subscriptions"""
def __init__(self, me, basepath, client) -> None: def __init__(self, account, basepath, client) -> None:
super().__init__( super().__init__(
me=me, basepath=basepath, client=client, name=NAME, methods=METHODS account=account,
basepath=basepath,
client=client,
name=NAME,
methods=METHODS,
) )
@check_wsclient @check_wsclient

Просмотреть файл

@ -1,3 +1,4 @@
from specklepy.logging import metrics
from specklepy.logging.exceptions import SpeckleException from specklepy.logging.exceptions import SpeckleException
from typing import List from typing import List
from gql import gql from gql import gql
@ -5,15 +6,19 @@ from specklepy.api.resource import ResourceBase
from specklepy.api.models import User from specklepy.api.models import User
NAME = "user" NAME = "user"
METHODS = ["get"] METHODS = ["get", "search", "update"]
class Resource(ResourceBase): class Resource(ResourceBase):
"""API Access class for users""" """API Access class for users"""
def __init__(self, me, basepath, client) -> None: def __init__(self, account, basepath, client) -> None:
super().__init__( super().__init__(
me=me, basepath=basepath, client=client, name=NAME, methods=METHODS account=account,
basepath=basepath,
client=client,
name=NAME,
methods=METHODS,
) )
self.schema = User self.schema = User
@ -26,6 +31,7 @@ class Resource(ResourceBase):
Returns: Returns:
User -- the retrieved user User -- the retrieved user
""" """
metrics.track(metrics.USER, self.account, {"name": "get"})
query = gql( query = gql(
""" """
query User($id: String) { query User($id: String) {
@ -62,6 +68,7 @@ class Resource(ResourceBase):
message="User search query must be at least 3 characters" message="User search query must be at least 3 characters"
) )
metrics.track(metrics.USER, self.account, {"name": "search"})
query = gql( query = gql(
""" """
query UserSearch($search_query: String!, $limit: Int!) { query UserSearch($search_query: String!, $limit: Int!) {
@ -98,6 +105,7 @@ class Resource(ResourceBase):
Returns: Returns:
bool -- True if your profile was updated successfully bool -- True if your profile was updated successfully
""" """
metrics.track(metrics.USER, self.account, {"name": "update"})
query = gql( query = gql(
""" """
mutation UserUpdate($user: UserUpdateInput!) { mutation UserUpdate($user: UserUpdateInput!) {

162
specklepy/api/wrapper.py Normal file
Просмотреть файл

@ -0,0 +1,162 @@
from warnings import warn
from urllib.parse import urlparse, unquote
from specklepy.api.credentials import (
Account,
get_account_from_token,
get_local_accounts,
)
from specklepy.logging import metrics
from specklepy.api.client import SpeckleClient
from specklepy.transports.server.server import ServerTransport
from specklepy.logging.exceptions import SpeckleException, SpeckleWarning
class StreamWrapper:
"""
The `StreamWrapper` gives you some handy helpers to deal with urls and get authenticated clients and transports.
Construct a `StreamWrapper` with a stream, branch, commit, or object URL. The corresponding ids will be stored
in the wrapper. If you have local accounts on the machine, you can use the `get_account` and `get_client` methods
to get a local account for the server. You can also pass a token into `get_client` if you don't have a corresponding
local account for the server.
```py
from specklepy.api.credentials import StreamWrapper
# provide any stream, branch, commit, object, or globals url
wrapper = StreamWrapper("https://speckle.xyz/streams/3073b96e86/commits/604bea8cc6")
# get an authenticated SpeckleClient if you have a local account for the server
client = wrapper.get_client()
# get an authenticated ServerTransport if you have a local account for the server
transport = wrapper.get_transport()
```
"""
stream_url: str = None
use_ssl: bool = True
host: str = None
stream_id: str = None
commit_id: str = None
object_id: str = None
branch_name: str = None
_client: SpeckleClient = None
_account: Account = None
def __repr__(self):
return f"StreamWrapper( server: {self.host}, stream_id: {self.stream_id}, type: {self.type} )"
def __str__(self) -> str:
return self.__repr__()
@property
def type(self) -> str:
if self.object_id:
return "object"
elif self.commit_id:
return "commit"
elif self.branch_name:
return "branch"
else:
return "stream" if self.stream_id else "invalid"
def __init__(self, url: str) -> None:
self.stream_url = url
parsed = urlparse(url)
self.host = parsed.netloc
self.use_ssl = parsed.scheme == "https"
segments = parsed.path.strip("/").split("/", 3)
metrics.track(metrics.STREAM_WRAPPER, self.get_account())
if not segments or len(segments) < 2:
raise SpeckleException(
f"Cannot parse {url} into a stream wrapper class - invalid URL provided."
)
while segments:
segment = segments.pop(0)
if segments and segment.lower() == "streams":
self.stream_id = segments.pop(0)
elif segments and segment.lower() == "commits":
self.commit_id = segments.pop(0)
elif segments and segment.lower() == "branches":
self.branch_name = unquote(segments.pop(0))
elif segments and segment.lower() == "objects":
self.object_id = segments.pop(0)
elif segment.lower() == "globals":
self.branch_name = "globals"
if segments:
self.commit_id = segments.pop(0)
else:
raise SpeckleException(
f"Cannot parse {url} into a stream wrapper class - invalid URL provided."
)
if not self.stream_id:
raise SpeckleException(
f"Cannot parse {url} into a stream wrapper class - no stream id found."
)
def get_account(self, token: str = None) -> Account:
"""
Gets an account object for this server from the local accounts db (added via Speckle Manager or a json file)
"""
if self._account and self._account.token:
return self._account
self._account = next(
(a for a in get_local_accounts() if self.host in a.serverInfo.url),
None,
)
if not self._account:
self._account = get_account_from_token(token, self.host)
if self._client:
self._client.authenticate_with_account(self._account)
return self._account
def get_client(self, token: str = None) -> SpeckleClient:
"""
Gets an authenticated client for this server. You may provide a token if there aren't any local accounts on this
machine. If no account is found and no token is provided, an unauthenticated client is returned.
Arguments:
token {str} -- optional token if no local account is available (defaults to None)
Returns:
SpeckleClient -- authenticated with a corresponding local account or the provided token
"""
if self._client and token is None:
return self._client
if not self._account or not self._account.token:
self.get_account(token)
if not self._client:
self._client = SpeckleClient(host=self.host, use_ssl=self.use_ssl)
if self._account.token is None and token is None:
warn(f"No local account found for server {self.host}", SpeckleWarning)
return self._client
if self._account.token:
self._client.authenticate_with_account(self._account)
else:
self._client.authenticate_with_token(token)
return self._client
def get_transport(self, token: str = None) -> ServerTransport:
"""
Gets a server transport for this stream using an authenticated client. If there is no local account for this
server and the client was not authenticated with a token, this will throw an exception.
Returns:
ServerTransport -- constructed for this stream with a pre-authenticated client
"""
if not self._account or not self._account.token:
self.get_account(token)
return ServerTransport(self.stream_id, account=self._account)

Просмотреть файл

@ -1,9 +1,12 @@
import json
import os import os
import socket
import sys
import queue import queue
import hashlib
import logging import logging
import requests import requests
import threading import threading
from specklepy.transports.sqlite import SQLiteTransport
""" """
Anonymous telemetry to help us understand how to make a better Speckle. Anonymous telemetry to help us understand how to make a better Speckle.
@ -11,25 +14,22 @@ This really helps us to deliver a better open source project and product!
""" """
TRACK = True TRACK = True
HOST_APP = "python" HOST_APP = "python"
PLATFORMS = {"win32": "Windows", "cygwin": "Windows", "darwin": "Mac OS X"}
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
METRICS_TRACKER = None METRICS_TRACKER = None
# actions # actions
RECEIVE = "receive" RECEIVE = "Receive"
SEND = "send" SEND = "Send"
STREAM_CREATE = "stream/create" STREAM = "Stream Action"
STREAM_GET = "stream/get" PERMISSION = "Permission Action"
STREAM_UPDATE = "stream/update" COMMIT = "Commit Action"
STREAM_DELETE = "stream/delete" BRANCH = "Branch Action"
STREAM_DETAILS = "stream/details" USER = "User Action"
STREAM_LIST = "stream/list" STREAM_WRAPPER = "Stream Wrapper"
STREAM_VIEW = "stream/view"
STREAM_SEARCH = "stream/search"
ACCOUNT_DEFAULT = "account/default" ACCOUNTS = "Get Local Accounts"
ACCOUNT_DETAILS = "account/details"
ACCOUNT_LIST = "account/list"
SERIALIZE = "serialization/serialize" SERIALIZE = "serialization/serialize"
DESERIALIZE = "serialization/deserialize" DESERIALIZE = "serialization/deserialize"
@ -40,44 +40,52 @@ def disable():
TRACK = False TRACK = False
def enable():
global TRACK
TRACK = True
def set_host_app(host_app: str): def set_host_app(host_app: str):
global HOST_APP global HOST_APP
HOST_APP = host_app HOST_APP = host_app
def track(action: str): def track(action: str, account: "Account" = None, custom_props: dict = None):
if not TRACK: if not TRACK:
return return
try: try:
global METRICS_TRACKER initialise_tracker(account)
if not METRICS_TRACKER:
METRICS_TRACKER = MetricsTracker()
page_params = {
"rec": 1,
"idsite": METRICS_TRACKER.site_id,
"uid": METRICS_TRACKER.suuid,
"action_name": action,
"url": f"http://connectors/{HOST_APP}/{action}",
"urlref": f"http://connectors/{HOST_APP}/{action}",
"_cvar": {"1": ["hostApplication", HOST_APP]},
}
event_params = { event_params = {
"rec": 1, "event": action,
"idsite": METRICS_TRACKER.site_id, "properties": {
"uid": MetricsTracker.suuid, "distinct_id": METRICS_TRACKER.last_user,
"_cvar": {"1": ["hostApplication", HOST_APP]}, "server_id": METRICS_TRACKER.last_server,
"e_c": HOST_APP, "token": METRICS_TRACKER.analytics_token,
"e_a": action, "hostApp": HOST_APP,
"$os": METRICS_TRACKER.platform,
"type": "action",
},
} }
if custom_props:
event_params["properties"].update(custom_props)
METRICS_TRACKER.queue.put_nowait([event_params, page_params]) METRICS_TRACKER.queue.put_nowait(event_params)
except Exception as ex: except Exception as ex:
# wrapping this whole thing in a try except as we never want a failure here to annoy users! # wrapping this whole thing in a try except as we never want a failure here to annoy users!
LOG.error("Error queueing metrics request: " + str(ex)) LOG.error("Error queueing metrics request: " + str(ex))
def initialise_tracker(account: "Account" = None):
global METRICS_TRACKER
if not METRICS_TRACKER:
METRICS_TRACKER = MetricsTracker()
if account and account.userInfo.email:
METRICS_TRACKER.set_last_user(account.userInfo.email)
if account and account.serverInfo.url:
METRICS_TRACKER.set_last_server(account.userInfo.email)
class Singleton(type): class Singleton(type):
_instances = {} _instances = {}
@ -88,10 +96,12 @@ class Singleton(type):
class MetricsTracker(metaclass=Singleton): class MetricsTracker(metaclass=Singleton):
matomo_url = "https://speckle.matomo.cloud/matomo.php" analytics_url = "https://analytics.speckle.systems/track?ip=1"
site_id = 2 analytics_token = "acd87c5a50b56df91a795e999812a3a4"
host_app = "python" user_ip = None
suuid = None last_user = None
last_server = None
platform = None
sending_thread = None sending_thread = None
queue = queue.Queue(1000) queue = queue.Queue(1000)
@ -99,25 +109,30 @@ class MetricsTracker(metaclass=Singleton):
self.sending_thread = threading.Thread( self.sending_thread = threading.Thread(
target=self._send_tracking_requests, daemon=True target=self._send_tracking_requests, daemon=True
) )
self.set_suuid() self.platform = PLATFORMS.get(sys.platform, "linux")
self.sending_thread.start() self.sending_thread.start()
self.user_ip = socket.gethostbyname(socket.gethostname())
def set_suuid(self): def set_last_user(self, email: str):
try: if not email:
file_path = os.path.join(SQLiteTransport.get_base_path("Speckle"), "suuid") return
with open(file_path, "r") as file: self.last_user = "@" + self.hash(email)
self.suuid = file.read()
except: def set_last_server(self, server: str):
self.suuid = "unknown-suuid" if not server:
return
self.last_server = self.hash(server)
def hash(self, value: str):
return hashlib.md5(value.lower().encode("utf-8")).hexdigest().upper()
def _send_tracking_requests(self): def _send_tracking_requests(self):
session = requests.Session() session = requests.Session()
while True: while True:
params = self.queue.get() event_params = [self.queue.get()]
try: try:
session.post(self.matomo_url, params=params[0]) session.post(self.analytics_url, json=event_params)
session.post(self.matomo_url, params=params[1])
except Exception as ex: except Exception as ex:
LOG.error("Error sending metrics request: " + str(ex)) LOG.error("Error sending metrics request: " + str(ex))

Просмотреть файл

@ -26,10 +26,7 @@ class MemoryTransport(AbstractTransport):
raise NotImplementedError raise NotImplementedError
def get_object(self, id: str) -> str or None: def get_object(self, id: str) -> str or None:
if id in self.objects: return self.objects[id] if id in self.objects else None
return self.objects[id]
else:
return None
def has_objects(self, id_list: List[str]) -> Dict[str, bool]: def has_objects(self, id_list: List[str]) -> Dict[str, bool]:
return {id: (id in self.objects) for id in id_list} return {id: (id in self.objects) for id in id_list}

Просмотреть файл

@ -5,6 +5,7 @@ from warnings import warn
from typing import Any, Dict, List from typing import Any, Dict, List
from specklepy.api.client import SpeckleClient from specklepy.api.client import SpeckleClient
from specklepy.api.credentials import Account, get_account_from_token
from specklepy.logging.exceptions import SpeckleException, SpeckleWarning from specklepy.logging.exceptions import SpeckleException, SpeckleWarning
from specklepy.transports.abstract_transport import AbstractTransport from specklepy.transports.abstract_transport import AbstractTransport
@ -18,7 +19,8 @@ class ServerTransport(AbstractTransport):
The `ServerTransport` can be authenticted two different ways: The `ServerTransport` can be authenticted two different ways:
1. by providing a `SpeckleClient` 1. by providing a `SpeckleClient`
2. by providing a `token` and `url` 2. by providing an `Account`
3. by providing a `token` and `url`
```py ```py
from specklepy.api import operations from specklepy.api import operations
@ -45,6 +47,7 @@ class ServerTransport(AbstractTransport):
_name = "RemoteTransport" _name = "RemoteTransport"
url: str = None url: str = None
stream_id: str = None stream_id: str = None
account: Account = None
saved_obj_count: int = 0 saved_obj_count: int = 0
session: requests.Session = None session: requests.Session = None
@ -52,38 +55,43 @@ class ServerTransport(AbstractTransport):
self, self,
stream_id: str, stream_id: str,
client: SpeckleClient = None, client: SpeckleClient = None,
account: Account = None,
token: str = None, token: str = None,
url: str = None, url: str = None,
**data: Any, **data: Any,
) -> None: ) -> None:
super().__init__(**data) super().__init__(**data)
# TODO: replace client with account or some other auth avenue if client is None and account is None and token is None and url is None:
if client is None and token is None and url is None:
raise SpeckleException( raise SpeckleException(
"You must provide either a client or a token and url to construct a ServerTransport." "You must provide either a client or a token and url to construct a ServerTransport."
) )
if client: if account:
self.account = account
url = account.serverInfo.url
elif client:
url = client.url url = client.url
if not client.me: if not client.account.token:
warn( warn(
SpeckleWarning( SpeckleWarning(
f"Unauthenticated Speckle Client provided to Server Transport for {self.url}. Receiving from private streams will fail." f"Unauthenticated Speckle Client provided to Server Transport for {self.url}. Receiving from private streams will fail."
) )
) )
else: else:
token = client.me["token"] self.account = client.account
else:
self.account = get_account_from_token(token, url)
self.stream_id = stream_id self.stream_id = stream_id
self.url = url self.url = url
self._batch_sender = BatchSender( self._batch_sender = BatchSender(
self.url, self.stream_id, token, max_batch_size_mb=1 self.url, self.stream_id, self.account.token, max_batch_size_mb=1
) )
self.session = requests.Session() self.session = requests.Session()
self.session.headers.update( self.session.headers.update(
{"Authorization": f"Bearer {token}", "Accept": "text/plain"} {"Authorization": f"Bearer {self.account.token}", "Accept": "text/plain"}
) )
def begin_write(self) -> None: def begin_write(self) -> None:

Просмотреть файл

@ -3,6 +3,7 @@ from specklepy.api import operations
from specklepy.api.client import SpeckleClient from specklepy.api.client import SpeckleClient
from specklepy.objects.base import Base from specklepy.objects.base import Base
from specklepy.transports.server import ServerTransport from specklepy.transports.server import ServerTransport
from specklepy.api.credentials import Account, get_account_from_token
from specklepy.logging.exceptions import SpeckleException, SpeckleWarning from specklepy.logging.exceptions import SpeckleException, SpeckleWarning
@ -10,12 +11,12 @@ def test_invalid_authentication():
client = SpeckleClient() client = SpeckleClient()
with pytest.warns(SpeckleWarning): with pytest.warns(SpeckleWarning):
client.authenticate("fake token") client.authenticate_with_token("fake token")
def test_invalid_send(): def test_invalid_send():
client = SpeckleClient() client = SpeckleClient()
client.me = {"token": "fake token"} client.account = Account(token="fake_token")
transport = ServerTransport("3073b96e86", client) transport = ServerTransport("3073b96e86", client)
with pytest.raises(SpeckleException): with pytest.raises(SpeckleException):
@ -24,8 +25,24 @@ def test_invalid_send():
def test_invalid_receive(): def test_invalid_receive():
client = SpeckleClient() client = SpeckleClient()
client.me = {"token": "fake token"} client.account = Account(token="fake_token")
transport = ServerTransport("fake stream", client) transport = ServerTransport("fake stream", client)
with pytest.raises(SpeckleException): with pytest.raises(SpeckleException):
operations.receive("fake object", transport) operations.receive("fake object", transport)
def test_account_from_token():
token = "fake token"
acct = get_account_from_token(token)
assert acct.token == token
def test_account_from_token_and_url():
token = "fake token"
url = "fake.server"
acct = get_account_from_token(token, url)
assert acct.token == token
assert acct.serverInfo.url == url

Просмотреть файл

@ -55,7 +55,7 @@ class TestSerialization:
# also try constructing server transport with token and url # also try constructing server transport with token and url
transport = ServerTransport( transport = ServerTransport(
stream_id=sample_stream.id, token=client.me["token"], url=client.url stream_id=sample_stream.id, token=client.account.token, url=client.url
) )
# use a fresh memory transport to force receiving from remote # use a fresh memory transport to force receiving from remote
received = operations.receive( received = operations.receive(

Просмотреть файл

@ -1,79 +1,81 @@
import pytest import pytest
from specklepy.api.credentials import StreamWrapper from specklepy.api.wrapper import StreamWrapper
class TestWrapper: def test_parse_stream():
def test_parse_stream(self): wrap = StreamWrapper("https://testing.speckle.dev/streams/a75ab4f10f")
wrap = StreamWrapper("https://testing.speckle.dev/streams/a75ab4f10f") assert wrap.type == "stream"
assert wrap.type == "stream"
def test_parse_branch(self):
wacky_wrap = StreamWrapper(
"https://testing.speckle.dev/streams/4c3ce1459c/branches/%F0%9F%8D%95%E2%AC%85%F0%9F%8C%9F%20you%20wat%3F"
)
wrap = StreamWrapper(
"https://testing.speckle.dev/streams/4c3ce1459c/branches/next%20level"
)
assert wacky_wrap.type == "branch"
assert wacky_wrap.branch_name == "🍕⬅🌟 you wat?"
assert wrap.type == "branch"
def test_parse_nested_branch(self): def test_parse_branch():
wrap = StreamWrapper( wacky_wrap = StreamWrapper(
"https://testing.speckle.dev/streams/4c3ce1459c/branches/izzy/dev" "https://testing.speckle.dev/streams/4c3ce1459c/branches/%F0%9F%8D%95%E2%AC%85%F0%9F%8C%9F%20you%20wat%3F"
) )
wrap = StreamWrapper(
"https://testing.speckle.dev/streams/4c3ce1459c/branches/next%20level"
)
assert wacky_wrap.type == "branch"
assert wacky_wrap.branch_name == "🍕⬅🌟 you wat?"
assert wrap.type == "branch"
assert wrap.branch_name == "izzy/dev"
assert wrap.type == "branch"
def test_parse_commit(self): def test_parse_nested_branch():
wrap = StreamWrapper( wrap = StreamWrapper(
"https://testing.speckle.dev/streams/4c3ce1459c/commits/8b9b831792" "https://testing.speckle.dev/streams/4c3ce1459c/branches/izzy/dev"
) )
assert wrap.type == "commit"
def test_parse_object(self): assert wrap.branch_name == "izzy/dev"
wrap = StreamWrapper( assert wrap.type == "branch"
"https://testing.speckle.dev/streams/a75ab4f10f/objects/5530363e6d51c904903dafc3ea1d2ec6"
)
assert wrap.type == "object"
def test_parse_globals_as_branch(self):
wrap = StreamWrapper("https://testing.speckle.dev/streams/0c6ad366c4/globals/")
assert wrap.type == "branch"
def test_parse_globals_as_commit(self): def test_parse_commit():
wrap = StreamWrapper( wrap = StreamWrapper(
"https://testing.speckle.dev/streams/0c6ad366c4/globals/abd3787893" "https://testing.speckle.dev/streams/4c3ce1459c/commits/8b9b831792"
) )
assert wrap.type == "commit" assert wrap.type == "commit"
#! NOTE: the following three tests may not pass locally if you have a `speckle.xyz` account in manager
def test_get_client_without_auth(self):
wrap = StreamWrapper(
"https://speckle.xyz/streams/4c3ce1459c/commits/8b9b831792"
)
client = wrap.get_client()
assert client is not None def test_parse_object():
wrap = StreamWrapper(
"https://testing.speckle.dev/streams/a75ab4f10f/objects/5530363e6d51c904903dafc3ea1d2ec6"
)
assert wrap.type == "object"
def test_get_new_client_with_token(self):
wrap = StreamWrapper(
"https://speckle.xyz/streams/4c3ce1459c/commits/8b9b831792"
)
client = wrap.get_client()
client = wrap.get_client(token="super-secret-token")
assert client.me["token"] == "super-secret-token" def test_parse_globals_as_branch():
wrap = StreamWrapper("https://testing.speckle.dev/streams/0c6ad366c4/globals/")
assert wrap.type == "branch"
def test_get_transport_with_token(self):
wrap = StreamWrapper(
"https://speckle.xyz/streams/4c3ce1459c/commits/8b9b831792"
)
client = wrap.get_client()
assert not client.me # unauthenticated bc no local accounts
transport = wrap.get_transport(token="super-secret-token") def test_parse_globals_as_commit():
wrap = StreamWrapper(
"https://testing.speckle.dev/streams/0c6ad366c4/globals/abd3787893"
)
assert wrap.type == "commit"
assert transport is not None
assert client.me["token"] == "super-secret-token" #! NOTE: the following three tests may not pass locally if you have a `speckle.xyz` account in manager
def test_get_client_without_auth():
wrap = StreamWrapper("https://speckle.xyz/streams/4c3ce1459c/commits/8b9b831792")
client = wrap.get_client()
assert client is not None
def test_get_new_client_with_token():
wrap = StreamWrapper("https://speckle.xyz/streams/4c3ce1459c/commits/8b9b831792")
client = wrap.get_client()
client = wrap.get_client(token="super-secret-token")
assert client.account.token == "super-secret-token"
def test_get_transport_with_token():
wrap = StreamWrapper("https://speckle.xyz/streams/4c3ce1459c/commits/8b9b831792")
client = wrap.get_client()
assert not client.account.token # unauthenticated bc no local accounts
transport = wrap.get_transport(token="super-secret-token")
assert transport is not None
assert client.account.token == "super-secret-token"