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)"]
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]]
name = "certifi"
version = "2021.10.8"
@ -148,35 +164,54 @@ category = "main"
optional = false
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]]
name = "gql"
version = "3.0.0b1"
version = "3.0.0"
description = "GraphQL client for Python"
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
aiohttp = {version = ">=3.7.1,<3.8.0", optional = true, markers = "extra == \"all\""}
graphql-core = ">=3.1.5,<3.2"
aiohttp = {version = ">=3.7.1,<3.9.0", optional = true, markers = "extra == \"all\""}
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_toolbelt = {version = ">=0.9.1,<1", 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"
[package.extras]
aiohttp = ["aiohttp (>=3.7.1,<3.8.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)"]
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"]
aiohttp = ["aiohttp (>=3.7.1,<3.9.0)"]
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)"]
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)"]
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_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"]
websockets = ["websockets (>=9,<10)"]
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 (==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 (>=10,<11)"]
[[package]]
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."
category = "main"
optional = false
@ -240,6 +275,14 @@ requirements_deprecated_finder = ["pipreqs", "pip-api"]
colors = ["colorama (>=0.4.3,<0.5.0)"]
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]]
name = "multidict"
version = "5.2.0"
@ -373,6 +416,17 @@ python-versions = "*"
[package.dependencies]
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]]
name = "regex"
version = "2021.11.10"
@ -410,6 +464,14 @@ python-versions = "*"
[package.dependencies]
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]]
name = "toml"
version = "0.10.2"
@ -471,6 +533,22 @@ category = "main"
optional = false
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]]
name = "yarl"
version = "1.7.2"
@ -499,7 +577,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes
[metadata]
lock-version = "1.1"
python-versions = "^3.6.5"
content-hash = "842f390b7c3b4c3a21d2113dc0aec26707b7698d748cbf1a195b9f4e29f40072"
content-hash = "78b3a6fe933735ef4f3c0dca34c08521ab2c11aceb2b7f5572846870d39d46f4"
[metadata.files]
aiohttp = [
@ -560,6 +638,10 @@ attrs = [
black = [
{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 = [
{file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
{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.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 = [
{file = "gql-3.0.0b1.tar.gz", hash = "sha256:a08195e73ed08785e1aef71a540e514f80dbfa711b9effba31ba15fcb687f1fd"},
{file = "gql-3.0.0.tar.gz", hash = "sha256:a21ff880a69caec8786be5cc6de7de6fc2f2b87547af8cd30746b9401ffd47b2"},
]
graphql-core = [
{file = "graphql-core-3.1.6.tar.gz", hash = "sha256:e65975b6a13878f9113a1fa5320760585b522d139944e005936b1b8358d0651a"},
{file = "graphql_core-3.1.6-py3-none-any.whl", hash = "sha256:c78d09596d347e1cffd266c5384abfedf43ed1eae08729773bebb3d527fe5a14"},
{file = "graphql-core-3.2.0.tar.gz", hash = "sha256:86e2a0be008bfde19ef78388de8a725a1d942a9190ca431c24a60837973803ce"},
{file = "graphql_core-3.2.0-py3-none-any.whl", hash = "sha256:0dda7e63676f119bb3d814621190fedad72fda07a8e9ab780bedd9f1957c6dc6"},
]
idna = [
{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.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 = [
{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"},
@ -794,6 +884,10 @@ pytest-ordering = [
{file = "pytest_ordering-0.6-py2-none-any.whl", hash = "sha256:27fba3fc265f5d0f8597e7557885662c1bdc1969497cd58aff6ed21c3b617de2"},
{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 = [
{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"},
@ -878,6 +972,10 @@ requests-toolbelt = [
{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"},
]
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 = [
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
{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-win_amd64.whl", hash = "sha256:85db8090ba94e22d964498a47fdd933b8875a1add6ebc514c7ac8703eb97bbf0"},
{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 = [
{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"
gql = {version = ">=3.0.0b1", extras = ["all"], allow-prereleases = true}
ujson = "^4.3.0"
Deprecated = "^1.2.13"
[tool.poetry.dev-dependencies]
black = "^20.8b1"

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

@ -1,5 +1,7 @@
import re
from warnings import warn
from deprecated import deprecated
from specklepy.api.credentials import Account, get_account_from_token
from specklepy.logging.exceptions import (
GraphQLException,
SpeckleException,
@ -39,9 +41,9 @@ class SpeckleClient:
client = SpeckleClient(host="speckle.xyz") # or whatever your host is
# 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()
client.authenticate(token=account.token)
client.authenticate_with_account(account)
# create a new stream. this returns the stream id
new_stream_id = client.stream.create(name="a shiny new stream")
@ -66,9 +68,9 @@ class SpeckleClient:
host = re.sub(r"((^\w+:|^)\/\/)|(\/$)", "", 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.me = None
self.account = Account()
self.httpclient = Client(
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)
def __repr__(self):
return (
f"SpeckleClient( server: {self.url}, authenticated: {self.me is not None} )"
)
return f"SpeckleClient( server: {self.url}, authenticated: {self.account.token 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:
"""Authenticate the client using a personal access token
The token is saved in the client object and a synchronous GraphQL entrypoint is created
@ -99,9 +103,31 @@ class SpeckleClient:
Arguments:
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 = {
"Authorization": f"Bearer {self.me['token']}",
"Authorization": f"Bearer {self.account.token}",
"Content-Type": "application/json",
}
httptransport = RequestsHTTPTransport(
@ -109,7 +135,7 @@ class SpeckleClient:
)
wstransport = WebsocketsTransport(
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.wsclient = Client(transport=wstransport)
@ -119,7 +145,7 @@ class SpeckleClient:
if isinstance(self.user.get(), GraphQLException):
warn(
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:
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(
me=self.me, basepath=self.url, client=self.httpclient
account=self.account, basepath=self.url, client=self.httpclient
)
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(
me=self.me, basepath=self.url, client=self.httpclient
account=self.account, basepath=self.url, client=self.httpclient
)
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(
me=self.me,
account=self.account,
basepath=self.ws_url,
client=self.wsclient,
)
@ -152,7 +180,9 @@ class SpeckleClient:
def __getattr__(self, name):
try:
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:
raise SpeckleException(
f"Method {name} is not supported by the SpeckleClient class"

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

@ -1,29 +1,25 @@
import os
from warnings import warn
from pydantic import BaseModel
from pydantic import BaseModel, Field
from typing import List, Optional
from urllib.parse import urlparse, unquote
from specklepy.logging import metrics
from specklepy.api.models import ServerInfo
from specklepy.api.client import SpeckleClient
from specklepy.transports.sqlite import SQLiteTransport
from specklepy.transports.server.server import ServerTransport
from specklepy.logging.exceptions import SpeckleException, SpeckleWarning
from specklepy.logging.exceptions import SpeckleException
class UserInfo(BaseModel):
name: str
email: str
name: Optional[str]
email: Optional[str]
company: Optional[str]
id: str
id: Optional[str]
class Account(BaseModel):
isDefault: bool = None
token: str
isDefault: bool = False
token: str = None
refreshToken: str = None
serverInfo: ServerInfo
userInfo: UserInfo
serverInfo: ServerInfo = Field(default_factory=ServerInfo)
userInfo: UserInfo = Field(default_factory=UserInfo)
id: str = None
def __repr__(self) -> str:
@ -32,6 +28,12 @@ class Account(BaseModel):
def __str__(self) -> str:
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]:
"""Gets all the accounts present in this environment
@ -42,7 +44,6 @@ def get_local_accounts(base_path: str = None) -> List[Account]:
Returns:
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)
json_path = os.path.join(account_storage._base_path, "Accounts")
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.",
ex,
)
metrics.track(
metrics.ACCOUNTS,
next(
(acc for acc in accounts if acc.isDefault),
accounts[0] if accounts else None,
),
)
return accounts
@ -75,7 +83,6 @@ def get_default_account(base_path: str = None) -> Account:
Returns:
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)
if not accounts:
return None
@ -84,147 +91,41 @@ def get_default_account(base_path: str = None) -> Account:
if not default:
default = accounts[0]
default.isDefault = True
metrics.initialise_tracker(default)
return default
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:
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,
)
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.
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} -- optional token if no local account is available (defaults to None)
token {str} -- the api token
Returns:
SpeckleClient -- authenticated with a corresponding local account or the provided token
Account -- the local account with this token or a shell account containing just the token and url if no local account is found
"""
if self._client and token is None:
return self._client
accounts = get_local_accounts()
if not accounts:
return Account.from_token(token, server_url)
if not self._account:
self.get_account()
acct = next((acc for acc in accounts if acc.token == token), None)
if acct:
return acct
if not self._client:
self._client = SpeckleClient(host=self.host, use_ssl=self.use_ssl)
if server_url:
url = server_url.lower()
acct = next(
(acc for acc in accounts if url in acc.serverInfo.url.lower()), None
)
if acct:
return acct
if self._account is None and token is None:
warn(f"No local account found for server {self.host}", SpeckleWarning)
return self._client
return Account.from_token(token, server_url)
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)
class StreamWrapper:
def __init__(self, url: str = None) -> None:
raise SpeckleException(
message="The StreamWrapper has moved as of v2.6.0! Please import from specklepy.api.wrapper",
exception=DeprecationWarning,
)

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

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

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

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

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

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

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

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

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

@ -10,9 +10,13 @@ METHODS = []
class Resource(ResourceBase):
"""API Access class for objects"""
def __init__(self, me, basepath, client) -> None:
def __init__(self, account, basepath, client) -> None:
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

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

@ -11,9 +11,13 @@ METHODS = ["get", "apps"]
class Resource(ResourceBase):
"""API Access class for the server"""
def __init__(self, me, basepath, client) -> None:
def __init__(self, account, basepath, client) -> None:
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:

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

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

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

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

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

@ -1,3 +1,4 @@
from specklepy.logging import metrics
from specklepy.logging.exceptions import SpeckleException
from typing import List
from gql import gql
@ -5,15 +6,19 @@ from specklepy.api.resource import ResourceBase
from specklepy.api.models import User
NAME = "user"
METHODS = ["get"]
METHODS = ["get", "search", "update"]
class Resource(ResourceBase):
"""API Access class for users"""
def __init__(self, me, basepath, client) -> None:
def __init__(self, account, basepath, client) -> None:
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
@ -26,6 +31,7 @@ class Resource(ResourceBase):
Returns:
User -- the retrieved user
"""
metrics.track(metrics.USER, self.account, {"name": "get"})
query = gql(
"""
query User($id: String) {
@ -62,6 +68,7 @@ class Resource(ResourceBase):
message="User search query must be at least 3 characters"
)
metrics.track(metrics.USER, self.account, {"name": "search"})
query = gql(
"""
query UserSearch($search_query: String!, $limit: Int!) {
@ -98,6 +105,7 @@ class Resource(ResourceBase):
Returns:
bool -- True if your profile was updated successfully
"""
metrics.track(metrics.USER, self.account, {"name": "update"})
query = gql(
"""
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 socket
import sys
import queue
import hashlib
import logging
import requests
import threading
from specklepy.transports.sqlite import SQLiteTransport
"""
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
HOST_APP = "python"
PLATFORMS = {"win32": "Windows", "cygwin": "Windows", "darwin": "Mac OS X"}
LOG = logging.getLogger(__name__)
METRICS_TRACKER = None
# actions
RECEIVE = "receive"
SEND = "send"
STREAM_CREATE = "stream/create"
STREAM_GET = "stream/get"
STREAM_UPDATE = "stream/update"
STREAM_DELETE = "stream/delete"
STREAM_DETAILS = "stream/details"
STREAM_LIST = "stream/list"
STREAM_VIEW = "stream/view"
STREAM_SEARCH = "stream/search"
RECEIVE = "Receive"
SEND = "Send"
STREAM = "Stream Action"
PERMISSION = "Permission Action"
COMMIT = "Commit Action"
BRANCH = "Branch Action"
USER = "User Action"
STREAM_WRAPPER = "Stream Wrapper"
ACCOUNT_DEFAULT = "account/default"
ACCOUNT_DETAILS = "account/details"
ACCOUNT_LIST = "account/list"
ACCOUNTS = "Get Local Accounts"
SERIALIZE = "serialization/serialize"
DESERIALIZE = "serialization/deserialize"
@ -40,42 +40,50 @@ def disable():
TRACK = False
def enable():
global TRACK
TRACK = True
def set_host_app(host_app: str):
global HOST_APP
HOST_APP = host_app
def track(action: str):
def track(action: str, account: "Account" = None, custom_props: dict = None):
if not TRACK:
return
try:
initialise_tracker(account)
event_params = {
"event": action,
"properties": {
"distinct_id": METRICS_TRACKER.last_user,
"server_id": METRICS_TRACKER.last_server,
"token": METRICS_TRACKER.analytics_token,
"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)
except Exception as ex:
# 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))
def initialise_tracker(account: "Account" = None):
global METRICS_TRACKER
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 = {
"rec": 1,
"idsite": METRICS_TRACKER.site_id,
"uid": MetricsTracker.suuid,
"_cvar": {"1": ["hostApplication", HOST_APP]},
"e_c": HOST_APP,
"e_a": action,
}
METRICS_TRACKER.queue.put_nowait([event_params, page_params])
except Exception as ex:
# 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))
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):
@ -88,10 +96,12 @@ class Singleton(type):
class MetricsTracker(metaclass=Singleton):
matomo_url = "https://speckle.matomo.cloud/matomo.php"
site_id = 2
host_app = "python"
suuid = None
analytics_url = "https://analytics.speckle.systems/track?ip=1"
analytics_token = "acd87c5a50b56df91a795e999812a3a4"
user_ip = None
last_user = None
last_server = None
platform = None
sending_thread = None
queue = queue.Queue(1000)
@ -99,25 +109,30 @@ class MetricsTracker(metaclass=Singleton):
self.sending_thread = threading.Thread(
target=self._send_tracking_requests, daemon=True
)
self.set_suuid()
self.platform = PLATFORMS.get(sys.platform, "linux")
self.sending_thread.start()
self.user_ip = socket.gethostbyname(socket.gethostname())
def set_suuid(self):
try:
file_path = os.path.join(SQLiteTransport.get_base_path("Speckle"), "suuid")
with open(file_path, "r") as file:
self.suuid = file.read()
except:
self.suuid = "unknown-suuid"
def set_last_user(self, email: str):
if not email:
return
self.last_user = "@" + self.hash(email)
def set_last_server(self, server: str):
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):
session = requests.Session()
while True:
params = self.queue.get()
event_params = [self.queue.get()]
try:
session.post(self.matomo_url, params=params[0])
session.post(self.matomo_url, params=params[1])
session.post(self.analytics_url, json=event_params)
except Exception as ex:
LOG.error("Error sending metrics request: " + str(ex))

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

@ -26,10 +26,7 @@ class MemoryTransport(AbstractTransport):
raise NotImplementedError
def get_object(self, id: str) -> str or None:
if id in self.objects:
return self.objects[id]
else:
return None
return self.objects[id] if id in self.objects else None
def has_objects(self, id_list: List[str]) -> Dict[str, bool]:
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 specklepy.api.client import SpeckleClient
from specklepy.api.credentials import Account, get_account_from_token
from specklepy.logging.exceptions import SpeckleException, SpeckleWarning
from specklepy.transports.abstract_transport import AbstractTransport
@ -18,7 +19,8 @@ class ServerTransport(AbstractTransport):
The `ServerTransport` can be authenticted two different ways:
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
from specklepy.api import operations
@ -45,6 +47,7 @@ class ServerTransport(AbstractTransport):
_name = "RemoteTransport"
url: str = None
stream_id: str = None
account: Account = None
saved_obj_count: int = 0
session: requests.Session = None
@ -52,38 +55,43 @@ class ServerTransport(AbstractTransport):
self,
stream_id: str,
client: SpeckleClient = None,
account: Account = None,
token: str = None,
url: str = None,
**data: Any,
) -> None:
super().__init__(**data)
# TODO: replace client with account or some other auth avenue
if client is None and token is None and url is None:
if client is None and account is None and token is None and url is None:
raise SpeckleException(
"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
if not client.me:
if not client.account.token:
warn(
SpeckleWarning(
f"Unauthenticated Speckle Client provided to Server Transport for {self.url}. Receiving from private streams will fail."
)
)
else:
token = client.me["token"]
self.account = client.account
else:
self.account = get_account_from_token(token, url)
self.stream_id = stream_id
self.url = url
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.headers.update(
{"Authorization": f"Bearer {token}", "Accept": "text/plain"}
{"Authorization": f"Bearer {self.account.token}", "Accept": "text/plain"}
)
def begin_write(self) -> None:

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

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

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

@ -1,13 +1,13 @@
import pytest
from specklepy.api.credentials import StreamWrapper
from specklepy.api.wrapper import StreamWrapper
class TestWrapper:
def test_parse_stream(self):
def test_parse_stream():
wrap = StreamWrapper("https://testing.speckle.dev/streams/a75ab4f10f")
assert wrap.type == "stream"
def test_parse_branch(self):
def test_parse_branch():
wacky_wrap = StreamWrapper(
"https://testing.speckle.dev/streams/4c3ce1459c/branches/%F0%9F%8D%95%E2%AC%85%F0%9F%8C%9F%20you%20wat%3F"
)
@ -18,7 +18,8 @@ class TestWrapper:
assert wacky_wrap.branch_name == "🍕⬅🌟 you wat?"
assert wrap.type == "branch"
def test_parse_nested_branch(self):
def test_parse_nested_branch():
wrap = StreamWrapper(
"https://testing.speckle.dev/streams/4c3ce1459c/branches/izzy/dev"
)
@ -26,54 +27,55 @@ class TestWrapper:
assert wrap.branch_name == "izzy/dev"
assert wrap.type == "branch"
def test_parse_commit(self):
def test_parse_commit():
wrap = StreamWrapper(
"https://testing.speckle.dev/streams/4c3ce1459c/commits/8b9b831792"
)
assert wrap.type == "commit"
def test_parse_object(self):
def test_parse_object():
wrap = StreamWrapper(
"https://testing.speckle.dev/streams/a75ab4f10f/objects/5530363e6d51c904903dafc3ea1d2ec6"
)
assert wrap.type == "object"
def test_parse_globals_as_branch(self):
def test_parse_globals_as_branch():
wrap = StreamWrapper("https://testing.speckle.dev/streams/0c6ad366c4/globals/")
assert wrap.type == "branch"
def test_parse_globals_as_commit(self):
def test_parse_globals_as_commit():
wrap = StreamWrapper(
"https://testing.speckle.dev/streams/0c6ad366c4/globals/abd3787893"
)
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"
)
#! 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(self):
wrap = StreamWrapper(
"https://speckle.xyz/streams/4c3ce1459c/commits/8b9b831792"
)
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.me["token"] == "super-secret-token"
assert client.account.token == "super-secret-token"
def test_get_transport_with_token(self):
wrap = StreamWrapper(
"https://speckle.xyz/streams/4c3ce1459c/commits/8b9b831792"
)
def test_get_transport_with_token():
wrap = StreamWrapper("https://speckle.xyz/streams/4c3ce1459c/commits/8b9b831792")
client = wrap.get_client()
assert not client.me # unauthenticated bc no local accounts
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.me["token"] == "super-secret-token"
assert client.account.token == "super-secret-token"