Skip to content

Commit 921e87d

Browse files
committed
Clean project from 5 years dust
1 parent 0a30bf0 commit 921e87d

File tree

7 files changed

+260
-189
lines changed

7 files changed

+260
-189
lines changed

.flake8

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[flake8]
2+
max-line-length = 100
3+
max-complexity = 10

Makefile

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
.NOTPARALLEL: ; # wait for this target to finish
2+
.EXPORT_ALL_VARIABLES: ; # send all vars to shell
3+
.PHONY: all # All targets are accessible for user
4+
.DEFAULT: help # Running Make will run the help target
5+
6+
PYTHON = @.venv/bin/python -m
7+
APP = bitrix24
8+
9+
# -------------------------------------------------------------------------------------------------
10+
# help: @ List available tasks on this project
11+
# -------------------------------------------------------------------------------------------------
12+
help:
13+
@grep -oE '^#.[a-zA-Z0-9]+:.*?@ .*$$' $(MAKEFILE_LIST) | tr -d '#' |\
14+
awk 'BEGIN {FS = ":.*?@ "}; {printf " make%-10s%s\n", $$1, $$2}'
15+
16+
# -------------------------------------------------------------------------------------------------
17+
# all: @ Apply all checks at once
18+
# -------------------------------------------------------------------------------------------------
19+
all: format lint test
20+
21+
# -------------------------------------------------------------------------------------------------
22+
# init: @ Setup local environment
23+
# -------------------------------------------------------------------------------------------------
24+
init: activate install
25+
26+
# -------------------------------------------------------------------------------------------------
27+
# update: @ Update package dependencies and install them
28+
# -------------------------------------------------------------------------------------------------
29+
update: compile install
30+
31+
# -------------------------------------------------------------------------------------------------
32+
# Activate virtual environment
33+
# -------------------------------------------------------------------------------------------------
34+
activate:
35+
@python3 -m venv .venv
36+
@. .venv/bin/activate
37+
38+
# -------------------------------------------------------------------------------------------------
39+
# Install packages to current environment
40+
# -------------------------------------------------------------------------------------------------
41+
install:
42+
$(PYTHON) pip install -e .[dev]
43+
44+
# -------------------------------------------------------------------------------------------------
45+
# test: @ Run tests using pytest
46+
# -------------------------------------------------------------------------------------------------
47+
test:
48+
$(PYTHON) pytest tests --cov=.
49+
50+
# -------------------------------------------------------------------------------------------------
51+
# lint: @ Checks the source code against coding standard rules and safety
52+
# -------------------------------------------------------------------------------------------------
53+
lint: lint.setup lint.flake8 lint.safety lint.docs
54+
55+
# -------------------------------------------------------------------------------------------------
56+
# format: @ Format source code and auto fix minor issues
57+
# -------------------------------------------------------------------------------------------------
58+
format:
59+
$(PYTHON) black --quiet --line-length=100 $(APP)
60+
$(PYTHON) isort $(APP)
61+
62+
# -------------------------------------------------------------------------------------------------
63+
# setup.py
64+
# -------------------------------------------------------------------------------------------------
65+
lint.setup:
66+
$(PYTHON) setup check -s
67+
68+
# -------------------------------------------------------------------------------------------------
69+
# flake8
70+
# -------------------------------------------------------------------------------------------------
71+
lint.flake8:
72+
$(PYTHON) flake8 --exclude=.venv,.eggs,*.egg,.git,migrations,__init__.py \
73+
--filename=*.py,*.pyx \
74+
--max-line-length=100 .
75+
76+
# -------------------------------------------------------------------------------------------------
77+
# safety
78+
# -------------------------------------------------------------------------------------------------
79+
lint.safety:
80+
$(PYTHON) safety check --full-report
81+
82+
# -------------------------------------------------------------------------------------------------
83+
# pydocstyle
84+
# -------------------------------------------------------------------------------------------------
85+
# Ignored error codes:
86+
# D100 Missing docstring in public module
87+
# D101 Missing docstring in public class
88+
# D102 Missing docstring in public method
89+
# D103 Missing docstring in public function
90+
# D104 Missing docstring in public package
91+
# D105 Missing docstring in magic method
92+
# D106 Missing docstring in public nested class
93+
# D107 Missing docstring in __init__
94+
lint.docs:
95+
$(PYTHON) pydocstyle --convention=numpy --add-ignore=D100,D101,D102,D103,D104,D105,D106,D107 .
96+
97+
# -------------------------------------------------------------------------------------------------
98+
# clean: @ Remove artifacts and temp files
99+
# -------------------------------------------------------------------------------------------------
100+
clean:
101+
@rm -rf .venv/ dist/ build/ *.egg-info/ .pytest_cache/ .coverage coverage.xml
102+
@find . | grep -E "\(__pycache__|\.pyc|\.pyo\$\)" | xargs rm -rf

bitrix24/__init__.py

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,11 @@
1-
# -*- coding: utf-8 -*-
2-
31
# ____ _ _ _ ____ _ _ ____ _____ ____ _____
42
# | __ )(_) |_ _ __(_)_ _|___ \| || | | _ \| ____/ ___|_ _|
53
# | _ \| | __| '__| \ \/ / __) | || |_ | |_) | _| \___ \ | |
64
# | |_) | | |_| | | |> < / __/|__ _| | _ <| |___ ___) || |
75
# |____/|_|\__|_| |_/_/\_\_____| |_| |_| \_\_____|____/ |_|
86

9-
10-
"""
11-
Bitrix24 REST library
12-
~~~~~~~~~~~~~~~~~~~~~
13-
14-
Bitrix24 REST provides easy way to communicate with bitrix24 portal over REST without OAuth 2.0.
15-
usage:
16-
17-
>>> from bitrix24 import Bitrix24
18-
>>> bx24 = Bitrix24('https://example.bitrix24.com/rest/1/33olqeits4avuyqu')
19-
>>> r = bx24.callMethod('crm.product.list')
20-
21-
Copyright (c) 2019 by Akop Kesheshyan.
22-
"""
23-
24-
__version__ = '1.1.1'
25-
__author__ = 'Akop Kesheshyan <akop.kesheshyan@icloud.com>'
26-
__license__ = 'MIT'
27-
__copyright__ = 'Copyright 2019 Akop Kesheshyan'
28-
297
from .bitrix24 import Bitrix24
30-
from .exceptions import BitrixError
8+
from .exceptions import BitrixError
9+
10+
__version__ = "2.0.0"
11+
__all__ = ["Bitrix24", "BitrixError"]

bitrix24/bitrix24.py

Lines changed: 88 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,61 @@
1-
# -*- coding: utf-8 -*-
1+
# ____ _ _ _ ____ _ _ ____ _____ ____ _____
2+
# | __ )(_) |_ _ __(_)_ _|___ \| || | | _ \| ____/ ___|_ _|
3+
# | _ \| | __| '__| \ \/ / __) | || |_ | |_) | _| \___ \ | |
4+
# | |_) | | |_| | | |> < / __/|__ _| | _ <| |___ ___) || |
5+
# |____/|_|\__|_| |_/_/\_\_____| |_| |_| \_\_____|____/ |_|
26

3-
"""
4-
Bitrix24
5-
~~~~~~~~~~~~
6-
7-
This module implements the Bitrix24 REST API.
8-
9-
:copyright: (c) 2019 by Akop Kesheshyan.
10-
11-
"""
127
import warnings
13-
14-
import requests
158
from time import sleep
169
from urllib.parse import urlparse
10+
11+
import requests
12+
1713
from .exceptions import BitrixError
1814

1915

20-
class Bitrix24(object):
21-
"""A user-created :class:`Bitrix24 <Bitrix24>` object.
22-
Used to sent to the server.
16+
class Bitrix24:
17+
"""
18+
Bitrix24 API class.
2319
24-
:param domain: REST call domain, including account name, user ID and secret code.
25-
:param timeout: (Optional) waiting for a response after a given number of seconds.
26-
Usage::
27-
>>> from bitrix24 import Bitrix24
28-
>>> bx24 = Bitrix24('https://example.bitrix24.com/rest/1/33olqeits4avuyqu')
29-
>>> bx24.callMethod('crm.product.list')
20+
Provides an easy way to communicate with Bitrix24 portal over REST without OAuth.
3021
"""
3122

32-
def __init__(self, domain, timeout=60, safe=True):
33-
"""Create Bitrix24 API object
34-
:param domain: str Bitrix24 webhook domain
35-
:param timeout: int Timeout for API request in seconds
23+
def __init__(self, domain: str, timeout: int = 60, safe: bool = True):
24+
"""
25+
Create Bitrix24 API object.
26+
27+
Parameters
28+
----------
29+
domain (str): Bitrix24 webhook domain
30+
timeout (int): Timeout for API request in seconds
3631
"""
3732
self.domain = self._prepare_domain(domain)
3833
self.timeout = timeout
3934
self.safe = safe
4035

41-
def _prepare_domain(self, domain):
36+
def _prepare_domain(self, domain: str):
4237
"""Normalize user passed domain to a valid one."""
43-
if domain == '' or not isinstance(domain, str):
44-
raise Exception('Empty domain')
38+
if not domain:
39+
raise Exception("Empty domain")
4540

4641
o = urlparse(domain)
47-
user_id, code = o.path.split('/')[2:4]
42+
user_id, code = o.path.split("/")[2:4]
4843
return "{0}://{1}/rest/{2}/{3}".format(o.scheme, o.netloc, user_id, code)
4944

50-
def _prepare_params(self, params, prev=''):
51-
"""Transforms list of params to a valid bitrix array."""
52-
ret = ''
45+
def _prepare_params(self, params, prev=""):
46+
"""
47+
Transform list of parameters to a valid bitrix array.
48+
49+
Parameters
50+
----------
51+
params (dict): Dictionary of parameters
52+
prev (str): Previous key
53+
54+
Returns
55+
-------
56+
str: Prepared parameters
57+
"""
58+
ret = ""
5359
if isinstance(params, dict):
5460
for key, value in params.items():
5561
if isinstance(value, dict):
@@ -60,11 +66,11 @@ def _prepare_params(self, params, prev=''):
6066
for offset, val in enumerate(value):
6167
if isinstance(val, dict):
6268
ret += self._prepare_params(
63-
val, "{0}[{1}][{2}]".format(prev, key, offset))
69+
val, "{0}[{1}][{2}]".format(prev, key, offset)
70+
)
6471
else:
6572
if prev:
66-
ret += "{0}[{1}][{2}]={3}&".format(
67-
prev, key, offset, val)
73+
ret += "{0}[{1}][{2}]={3}&".format(prev, key, offset, val)
6874
else:
6975
ret += "{0}[{1}]={2}&".format(key, offset, val)
7076
else:
@@ -74,53 +80,63 @@ def _prepare_params(self, params, prev=''):
7480
ret += "{0}={1}&".format(key, value)
7581
return ret
7682

77-
def callMethod(self, method, **params):
78-
"""Calls a REST method with specified parameters.
79-
80-
:param url: REST method name.
81-
:param \*\*params: Optional arguments which will be converted to a POST request string.
82-
:return: Returning the REST method response as an array, an object or a scalar
83-
"""
84-
83+
def request(self, url, method, p):
84+
if method.rsplit(".", 1)[0] in ["add", "update", "delete", "set"]:
85+
r = requests.post(url, data=p, timeout=self.timeout, verify=self.safe).json()
86+
else:
87+
r = requests.get(url, params=p, timeout=self.timeout, verify=self.safe)
8588
try:
86-
url = '{0}/{1}.json'.format(self.domain, method)
89+
r = r.json()
90+
except requests.exceptions.JSONDecodeError:
91+
warnings.warn("bitrix24: JSON decode error...")
92+
if r.status_code == 403:
93+
warnings.warn(
94+
f"bitrix24: Forbidden: {method}. "
95+
"Check your bitrix24 webhook settings. Returning None! "
96+
)
97+
return None
98+
elif r.ok:
99+
return r.content
100+
101+
def callMethod(self, method: str, **params):
102+
"""Call a REST method with specified parameters.
103+
104+
Parameters
105+
----------
106+
method (str): REST method name
107+
params (dict): Optional arguments which will be converted to a POST request string
108+
109+
Returns
110+
-------
111+
Returning the REST method response as an array, an object or a scalar
112+
"""
113+
if not method or len(method.split(".")) < 3:
114+
raise BitrixError("Empty method")
87115

116+
try:
117+
url = "{0}/{1}.json".format(self.domain, method)
88118
p = self._prepare_params(params)
89-
90-
if method.rsplit('.', 1)[0] in ['add', 'update', 'delete', 'set']:
91-
r = requests.post(url, data=p, timeout=self.timeout, verify=self.safe).json()
92-
else:
93-
r = requests.get(url, params=p, timeout=self.timeout, verify=self.safe)
94-
try:
95-
r = r.json()
96-
except requests.exceptions.JSONDecodeError as e:
97-
warnings.warn("bitrix24: JSON decode error...")
98-
if r.status_code == 403:
99-
warnings.warn(f"bitrix24: Forbidden: {method}. Check your bitrix24 webhook settings. Returning None! ")
100-
return None
101-
elif r.ok:
102-
return r.content
103-
104-
105-
119+
r = self.request(url, method, p)
120+
if not r:
121+
return None
106122
except ValueError:
107-
if r['error'] not in 'QUERY_LIMIT_EXCEEDED':
108-
raise BitrixError(r)
123+
if r["error"] not in "QUERY_LIMIT_EXCEEDED":
124+
raise BitrixError(message=r["error_description"], code=r["error"])
109125
# Looks like we need to wait until expires limitation time by Bitrix24 API
110126
sleep(2)
111127
return self.callMethod(method, **params)
112128

113-
if 'error' in r:
129+
if "error" in r:
114130
raise BitrixError(r)
115-
if 'start' not in params:
116-
params['start'] = 0
117-
if 'next' in r and r['total'] > params['start']:
118-
params['start'] += 50
131+
if "start" not in params:
132+
params["start"] = 0
133+
if "next" in r and r["total"] > params["start"]:
134+
params["start"] += 50
119135
data = self.callMethod(method, **params)
120-
if isinstance(r['result'], dict):
121-
result = r['result'].copy()
136+
if isinstance(r["result"], dict):
137+
result = r["result"].copy()
122138
result.update(data)
123139
else:
124-
result = r['result'] + data
140+
result = r["result"] + data
125141
return result
126-
return r['result']
142+
return r["result"]

bitrix24/exceptions.py

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
1-
# -*- coding: utf-8 -*-
2-
3-
"""
4-
Bitrix24.exceptions
5-
~~~~~~~~~~~~~~~~~~~
6-
7-
This module contains the set of Bitrix24 REST exceptions.
8-
9-
:copyright: (c) 2019 by Akop Kesheshyan.
10-
11-
"""
1+
# ____ _ _ _ ____ _ _ ____ _____ ____ _____
2+
# | __ )(_) |_ _ __(_)_ _|___ \| || | | _ \| ____/ ___|_ _|
3+
# | _ \| | __| '__| \ \/ / __) | || |_ | |_) | _| \___ \ | |
4+
# | |_) | | |_| | | |> < / __/|__ _| | _ <| |___ ___) || |
5+
# |____/|_|\__|_| |_/_/\_\_____| |_| |_| \_\_____|____/ |_|
126

137

148
class BitrixError(ValueError):
15-
def __init__(self, response):
16-
super().__init__(response['error_description'])
17-
self.code = response['error']
9+
def __init__(self, message: str, code: int = 500):
10+
self.message = message
11+
self.code = code

0 commit comments

Comments
 (0)