diff --git a/.gitignore b/.gitignore index b6e4761..ac0f320 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,5 @@ dmypy.json # Pyre type checker .pyre/ + +examples/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..4a21916 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,20 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.2.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + + - repo: https://github.com/pre-commit/mirrors-autopep8 + rev: v1.4.4 + hooks: + - id: autopep8 + + - repo: https://github.com/pycqa/isort + rev: 5.8.0 + hooks: + - id: isort + name: isort (python) diff --git a/README.md b/README.md index 1208c13..364a8d8 100644 --- a/README.md +++ b/README.md @@ -1 +1,53 @@ -# thepeer-sdk-python \ No newline at end of file +# Thepeer Python SDK + +![GitHub issues](https://img.shields.io/github/issues/Emmarex/thepeer-sdk-python) +![PyPI - Downloads](https://img.shields.io/pypi/dm/thepeer-sdk) +[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) + +Python SDK for [Thepeer](https://thepeer.co/). + +## Quick Start + +1. Install thepeer-sdk + +```bash +pip install thepeer-sdk +``` + +2. Signup to get your API keys [here](https://dashboard.thepeer.co/login) + +## Usage + + +### Initiate +```python +from thepeer_sdk import ThepeerSdkClient + +thepeer_sdk_client = ThepeerSdkClient( + secret_key="SECRET_KEY_GOES_HERE" +) + +# Get the list of all indexed users +thepeer_sdk_client.list_users() +``` + +### Available Methods +#### User +- index_user +- list_users +- update_user +- delete_user + +## Upgrade + +```bash +pip install --upgrade thepeer-sdk +``` + +## Extra + +Visit the official [Thepeer documentation](https://docs.thepeer.co/) for more information. + + +## License +See LICENSE. diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..a93c071 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,375 @@ +[[package]] +name = "autopep8" +version = "1.6.0" +description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +pycodestyle = ">=2.8.0" +toml = "*" + +[[package]] +name = "backports.entry-points-selectable" +version = "1.1.1" +description = "Compatibility shim providing selectable entry points for older implementations" +category = "dev" +optional = false +python-versions = ">=2.7" + +[package.dependencies] +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest", "pytest-flake8", "pytest-cov", "pytest-black (>=0.3.7)", "pytest-mypy", "pytest-checkdocs (>=2.4)", "pytest-enabler (>=1.0.1)"] + +[[package]] +name = "certifi" +version = "2021.10.8" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "cfgv" +version = "3.3.1" +description = "Validate configuration and produce human readable error messages." +category = "dev" +optional = false +python-versions = ">=3.6.1" + +[[package]] +name = "charset-normalizer" +version = "2.0.9" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.5.0" + +[package.extras] +unicode_backport = ["unicodedata2"] + +[[package]] +name = "distlib" +version = "0.3.4" +description = "Distribution utilities" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "filelock" +version = "3.4.0" +description = "A platform independent file lock." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"] +testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"] + +[[package]] +name = "identify" +version = "2.4.0" +description = "File identification library for Python" +category = "dev" +optional = false +python-versions = ">=3.6.1" + +[package.extras] +license = ["ukkonen"] + +[[package]] +name = "idna" +version = "3.3" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "importlib-metadata" +version = "4.9.0" +description = "Read metadata from Python packages" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} +zipp = ">=0.5" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +perf = ["ipython"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] + +[[package]] +name = "nodeenv" +version = "1.6.0" +description = "Node.js virtual environment builder" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "platformdirs" +version = "2.4.0" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] +test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] + +[[package]] +name = "pre-commit" +version = "2.16.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +category = "dev" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +toml = "*" +virtualenv = ">=20.0.8" + +[[package]] +name = "pycodestyle" +version = "2.8.0" +description = "Python style guide checker" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "pyyaml" +version = "6.0" +description = "YAML parser and emitter for Python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "requests" +version = "2.26.0" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} +idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "typing-extensions" +version = "4.0.1" +description = "Backported and Experimental Type Hints for Python 3.6+" +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "urllib3" +version = "1.26.7" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.extras] +brotli = ["brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "virtualenv" +version = "20.10.0" +description = "Virtual Python Environment builder" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[package.dependencies] +"backports.entry-points-selectable" = ">=1.0.4" +distlib = ">=0.3.1,<1" +filelock = ">=3.2,<4" +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +platformdirs = ">=2,<3" +six = ">=1.9.0,<2" + +[package.extras] +docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"] +testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"] + +[[package]] +name = "zipp" +version = "3.6.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] + +[metadata] +lock-version = "1.1" +python-versions = "3.7.12" +content-hash = "3f686b25cc971984a5aa31faed3b2248d020018bf83a30d565a0b1931a3308c8" + +[metadata.files] +autopep8 = [ + {file = "autopep8-1.6.0-py2.py3-none-any.whl", hash = "sha256:ed77137193bbac52d029a52c59bec1b0629b5a186c495f1eb21b126ac466083f"}, + {file = "autopep8-1.6.0.tar.gz", hash = "sha256:44f0932855039d2c15c4510d6df665e4730f2b8582704fa48f9c55bd3e17d979"}, +] +"backports.entry-points-selectable" = [ + {file = "backports.entry_points_selectable-1.1.1-py2.py3-none-any.whl", hash = "sha256:7fceed9532a7aa2bd888654a7314f864a3c16a4e710b34a58cfc0f08114c663b"}, + {file = "backports.entry_points_selectable-1.1.1.tar.gz", hash = "sha256:914b21a479fde881635f7af5adc7f6e38d6b274be32269070c53b698c60d5386"}, +] +certifi = [ + {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, + {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, +] +cfgv = [ + {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, + {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, +] +charset-normalizer = [ + {file = "charset-normalizer-2.0.9.tar.gz", hash = "sha256:b0b883e8e874edfdece9c28f314e3dd5badf067342e42fb162203335ae61aa2c"}, + {file = "charset_normalizer-2.0.9-py3-none-any.whl", hash = "sha256:1eecaa09422db5be9e29d7fc65664e6c33bd06f9ced7838578ba40d58bdf3721"}, +] +distlib = [ + {file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"}, + {file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"}, +] +filelock = [ + {file = "filelock-3.4.0-py3-none-any.whl", hash = "sha256:2e139a228bcf56dd8b2274a65174d005c4a6b68540ee0bdbb92c76f43f29f7e8"}, + {file = "filelock-3.4.0.tar.gz", hash = "sha256:93d512b32a23baf4cac44ffd72ccf70732aeff7b8050fcaf6d3ec406d954baf4"}, +] +identify = [ + {file = "identify-2.4.0-py2.py3-none-any.whl", hash = "sha256:eba31ca80258de6bb51453084bff4a923187cd2193b9c13710f2516ab30732cc"}, + {file = "identify-2.4.0.tar.gz", hash = "sha256:a33ae873287e81651c7800ca309dc1f84679b763c9c8b30680e16fbfa82f0107"}, +] +idna = [ + {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, + {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, +] +importlib-metadata = [ + {file = "importlib_metadata-4.9.0-py3-none-any.whl", hash = "sha256:e8b45564028bc25f8c99f546616112a6df5de6655893d7eb74c9a99680dc9751"}, + {file = "importlib_metadata-4.9.0.tar.gz", hash = "sha256:ee50794eccb0ec340adbc838344ebb9a6ff2bcba78f752d31fc716497e2149d6"}, +] +nodeenv = [ + {file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"}, + {file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"}, +] +platformdirs = [ + {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, + {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, +] +pre-commit = [ + {file = "pre_commit-2.16.0-py2.py3-none-any.whl", hash = "sha256:758d1dc9b62c2ed8881585c254976d66eae0889919ab9b859064fc2fe3c7743e"}, + {file = "pre_commit-2.16.0.tar.gz", hash = "sha256:fe9897cac830aa7164dbd02a4e7b90cae49630451ce88464bca73db486ba9f65"}, +] +pycodestyle = [ + {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, + {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, +] +pyyaml = [ + {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, + {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, + {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, + {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, + {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, + {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, + {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, + {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, + {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, + {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, + {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, + {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, + {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, + {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, + {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, +] +requests = [ + {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, + {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, +] +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"}, +] +typing-extensions = [ + {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"}, + {file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"}, +] +urllib3 = [ + {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, + {file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"}, +] +virtualenv = [ + {file = "virtualenv-20.10.0-py2.py3-none-any.whl", hash = "sha256:4b02e52a624336eece99c96e3ab7111f469c24ba226a53ec474e8e787b365814"}, + {file = "virtualenv-20.10.0.tar.gz", hash = "sha256:576d05b46eace16a9c348085f7d0dc8ef28713a2cabaa1cf0aea41e8f12c9218"}, +] +zipp = [ + {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"}, + {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..f903a12 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,18 @@ +[tool.poetry] +name = "thepeer-sdk" +version = "0.0.1" +description = "Python SDK for Thepeer" +authors = ["Oluwafemi Tairu "] +license = "Apache-2.0" + +[tool.poetry.dependencies] +python = "3.7.12" +requests = "^2.26.0" + +[tool.poetry.dev-dependencies] +pre-commit = "^2.16.0" +autopep8 = "^1.6.0" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..87dde91 --- /dev/null +++ b/setup.py @@ -0,0 +1,32 @@ +from setuptools import find_packages, setup + +with open("README.md", "r") as fh: + long_description = fh.read() + +setup( + name='thepeer-sdk', + version='0.0.1', + author="Tairu Oluwafemi Emmanuel", + author_email="developer.emmarex@gmail.com", + description="", + long_description=long_description, + long_description_content_type="text/markdown", + url="https://github.com/Emmarex/thepeer-sdk-python", + download_url="", + keywords=['thepeer'], + include_package_data=True, + packages=find_packages(), + python_requires='~=3.7', + classifiers=[ + "Natural Language :: English", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.10" + "Programming Language :: Python :: 3.11" + "License :: OSI Approved :: Apache Software License", + "Development Status :: 4 - Beta", + # "Development Status :: 6 - Mature", + "Intended Audience :: Developers" + ], +) diff --git a/thepeer_sdk/__init__.py b/thepeer_sdk/__init__.py new file mode 100644 index 0000000..211ee11 --- /dev/null +++ b/thepeer_sdk/__init__.py @@ -0,0 +1,3 @@ +__api_version__ = '0.0.1' + +from .core import ThepeerSdkClient diff --git a/thepeer_sdk/core/__init__.py b/thepeer_sdk/core/__init__.py new file mode 100644 index 0000000..b30b150 --- /dev/null +++ b/thepeer_sdk/core/__init__.py @@ -0,0 +1,2 @@ + +from .sdk_client import ThepeerSdkClient diff --git a/thepeer_sdk/core/sdk_client.py b/thepeer_sdk/core/sdk_client.py new file mode 100644 index 0000000..0ac2018 --- /dev/null +++ b/thepeer_sdk/core/sdk_client.py @@ -0,0 +1,18 @@ +from thepeer_sdk.core.users import Users +from thepeer_sdk.exceptions import ThepeerSDKException +from thepeer_sdk.utils import ApiClient + + +class ThepeerSdkClient( + Users +): + """ + :param secret_key: + secret_key to use with this API. **REQUIRED** + """ + + def __init__(self, secret_key: str): + if not secret_key or secret_key.strip() == "": + raise ThepeerSDKException("`secret_key` is required") + self.API_BASE_URL = "https://api.thepeer.co" + self.api_client = ApiClient(secret_key) diff --git a/thepeer_sdk/core/users.py b/thepeer_sdk/core/users.py new file mode 100644 index 0000000..1e09a20 --- /dev/null +++ b/thepeer_sdk/core/users.py @@ -0,0 +1,91 @@ +from thepeer_sdk.exceptions import ThepeerSDKException + + +class Users(): + + def __init__(self) -> None: + if hasattr(self, "api_client"): + self.api_client = self.api_client + else: + raise ThepeerSDKException("api_client instance is required") + + if hasattr(self, "API_BASE_URL"): + self.API_BASE_URL = self.api_client + else: + raise ThepeerSDKException("API_BASE_URL is required") + + def index_user(self, name: str, identifier: str, email: str) -> dict: + """ + Index a particular user on Thepeer + + :param name: str + + :param identifier: str + unique user identifier + + :param email: str + + """ + return self.api_client.make_post( + url=f'{self.API_BASE_URL}/users', + data={ + "name": name, + "identifier": identifier, + "email": email + } + ) + + def list_users(self, page: int = 1, perPage: int = 10) -> dict: + """ + Get the list of all indexed users + + :param page: int + page number to return + + :param perPage: int + amount of records to return per page + """ + return self.api_client.make_get( + url=f'{self.API_BASE_URL}/users', + ) + + def update_user(self, user_ref: str, user_identifier: str) -> dict: + """ + Update your user's identifier when they make a profile update + to their identifier on your platform. + + :param user_ref: str + the reference returned when the user was indexed + + :param user_identifier: str + unique user identifier + **NOTE**: You cannot update an identifier from username to email and vice versa + """ + + if not user_ref or user_ref.strip() == "": + raise ThepeerSDKException( + "`user_ref` cannot be an empty string") + + if not user_identifier or user_identifier.strip() == "": + raise ThepeerSDKException( + "`user_identifier` cannot be an empty string") + + return self.api_client.make_put( + url=f'{self.API_BASE_URL}/users/{user_ref}', + data={ + "identifier": user_identifier + } + ) + + def delete_user(self, user_ref: str) -> dict: + """ + Delete a user in the event that a user deactivates their + account on your platform + + :param user_ref: str + the reference returned when the user was indexed + """ + + return self.api_client.make_delete( + url=f'{self.API_BASE_URL}/users/{user_ref}', + ) diff --git a/thepeer_sdk/exceptions.py b/thepeer_sdk/exceptions.py new file mode 100644 index 0000000..dd1a890 --- /dev/null +++ b/thepeer_sdk/exceptions.py @@ -0,0 +1,69 @@ + +class ThepeerSDKException(Exception): + """ + An Exception raised when the SDK is used incorrectly. + """ + + @property + def message(self): + return self.__dict__.get('message', None) or getattr(self, 'args')[0] + + +class ThepeerSDKForbiddenException(Exception): + """ + An Exception raised when your request is forbidden + """ + + @property + def message(self): + return self.__dict__.get('message', None) or getattr(self, 'args')[0] + + +class ThepeerSDKUnauthorizedException(Exception): + """ + An Exception raised when your request contains an invalid secret key + """ + + @property + def message(self): + return self.__dict__.get('message', None) or getattr(self, 'args')[0] + + +class ThepeerSDKInvalidPayloadException(Exception): + """ + An Exception raised when your request contains invalid payload + """ + + @property + def message(self): + return self.__dict__.get('message', None) or getattr(self, 'args')[0] + + +class ThepeerSDKInvalidResourceException(Exception): + """ + An Exception raised when your request is to an invalid URL + """ + + @property + def message(self): + return self.__dict__.get('message', None) or getattr(self, 'args')[0] + + +class ThepeerSDKServiceUnavailableException(Exception): + """ + An Exception raised when the server is not reachable + """ + + @property + def message(self): + return self.__dict__.get('message', None) or getattr(self, 'args')[0] + + +class ThepeerSDKServerErrorException(Exception): + """ + An Exception raised when there is a server error + """ + + @property + def message(self): + return self.__dict__.get('message', None) or getattr(self, 'args')[0] diff --git a/thepeer_sdk/utils/__init__.py b/thepeer_sdk/utils/__init__.py new file mode 100644 index 0000000..d534320 --- /dev/null +++ b/thepeer_sdk/utils/__init__.py @@ -0,0 +1 @@ +from .apiclient import ApiClient diff --git a/thepeer_sdk/utils/apiclient.py b/thepeer_sdk/utils/apiclient.py new file mode 100644 index 0000000..81c3add --- /dev/null +++ b/thepeer_sdk/utils/apiclient.py @@ -0,0 +1,103 @@ +import json + +from requests import Response, request + +from thepeer_sdk import __api_version__, exceptions +from thepeer_sdk.exceptions import (ThepeerSDKForbiddenException, + ThepeerSDKInvalidPayloadException, + ThepeerSDKInvalidResourceException, + ThepeerSDKServerErrorException, + ThepeerSDKServiceUnavailableException, + ThepeerSDKUnauthorizedException) + + +class ApiClient(object): + """ + Thepeer Python SDK API Client + """ + + def __init__(self, secret_key: str): + """ + Create and instance of Thepeer's API Client + This API CLient will be used to make calls to Thepeer's API + """ + self.__baseHeaders = { + 'User-Agent': f'Thepeer Python SDK v{__api_version__}', + 'x-sdk-type': 'Python', + 'x-sdk-version': __api_version__, + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'X-Api-Key': secret_key + } + + def _process_response(self, response: Response) -> dict: + response_json = response.json() + if response.status_code == 201 or response.status_code == 200: + return response_json + elif response.status_code == 401: + raise ThepeerSDKUnauthorizedException( + f'{response.reason}: {response_json["message"]}') + elif response.status_code == 403: + raise ThepeerSDKForbiddenException( + f'{response.reason}: {response_json["message"]}') + elif response.status_code == 404: + raise ThepeerSDKInvalidResourceException( + f'{response.reason}: {response_json["message"]}') + elif response.status_code == 422: + for item in response_json['errors'].values(): + raise ThepeerSDKInvalidPayloadException(item[0]) + raise + elif response.status_code == 406: + raise ThepeerSDKForbiddenException( + f'{response.reason}: {response_json["message"]}') + elif response.status_code == 503: + raise ThepeerSDKServiceUnavailableException( + f'{response.reason}: {response_json["message"]}') + else: + raise ThepeerSDKServerErrorException( + f'{response.reason}: {response_json["message"]}') + + def _make_request(self, method: str, route: str, payload: dict, query_params: dict = {}, request_files: list = None) -> dict: + response = request( + method=method, + url=route, + headers=self.__baseHeaders, + files=request_files, + data=payload if request_files is not None else json.dumps(payload), + params=query_params + ) + return self._process_response(response) + + def make_post(self, url: str, params: dict = {}, data: dict = {}, files: list = None) -> dict: + return self._make_request( + method="POST", + route=url, + payload=data, + query_params=params, + request_files=files + ) + + def make_get(self, url: str, params: dict = {}, data: dict = {}) -> dict: + return self._make_request( + method="GET", + route=url, + payload=data, + query_params=params + ) + + def make_put(self, url: str, params: dict = {}, data: dict = {}, files=None) -> dict: + return self._make_request( + method="PUT", + route=url, + payload=data, + query_params=params, + request_files=files + ) + + def make_delete(self, url: str, params: dict = {}) -> dict: + return self._make_request( + method="DELETE", + route=url, + payload={}, + query_params=params + )