PyOdoo 0.8.0__tar.gz → 0.8.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyodoo-0.8.0 → pyodoo-0.8.1}/PKG-INFO +5 -2
- {pyodoo-0.8.0 → pyodoo-0.8.1}/PyOdoo.egg-info/PKG-INFO +5 -2
- {pyodoo-0.8.0 → pyodoo-0.8.1}/PyOdoo.egg-info/SOURCES.txt +1 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/README.md +2 -1
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/api.py +44 -11
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/constants.py +1 -1
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/model.py +3 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/samples/contacts.py +1 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/samples/contacts_async.py +1 -0
- pyodoo-0.8.1/pyodoo/transport.py +78 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyproject.toml +2 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/LICENSE +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/PyOdoo.egg-info/dependency_links.txt +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/PyOdoo.egg-info/requires.txt +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/PyOdoo.egg-info/top_level.txt +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/__init__.py +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/active_status_choice.py +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/boolean_operator.py +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/compare_type.py +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/filter.py +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/implementation.py +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/message_subtype.py +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/python_code.py +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/samples/__init__.py +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/samples/awaitable.py +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/samples/python_code.py +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/samples/sql_excel_query.py +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/sql_excel_query.py +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/v12/__init__.py +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/setup.cfg +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/tests/test_compare_types.py +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/tests/test_contacts.py +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/tests/test_python_code.py +0 -0
- {pyodoo-0.8.0 → pyodoo-0.8.1}/tests/test_sql_excel_query.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyOdoo
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.1
|
|
4
4
|
Summary: API for Odoo
|
|
5
5
|
Author-email: Fabio Castelli <muflone@muflone.com>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -12,11 +12,13 @@ Classifier: Development Status :: 1 - Planning
|
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
19
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
20
|
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Requires-Python: >=3.9
|
|
20
22
|
Description-Content-Type: text/markdown
|
|
21
23
|
License-File: LICENSE
|
|
22
24
|
Requires-Dist: xlrd~=2.0
|
|
@@ -25,7 +27,6 @@ Dynamic: license-file
|
|
|
25
27
|
|
|
26
28
|
# PyOdoo
|
|
27
29
|
|
|
28
|
-
[](https://www.travis-ci.com/github/muflone/pyodoo)
|
|
29
30
|
[](https://circleci.com/gh/muflone/pyodoo)
|
|
30
31
|
[](https://github.com/muflone/pyodoo/actions/workflows/python-3.9.yml)
|
|
31
32
|
[](https://github.com/muflone/pyodoo/actions/workflows/python-3.10.yml)
|
|
@@ -65,3 +66,5 @@ Currently the following implementations are provided:
|
|
|
65
66
|
# Usage
|
|
66
67
|
|
|
67
68
|
Please see the **samples** and the **tests** folders for some usage examples.
|
|
69
|
+
|
|
70
|
+
Examples and documentation is available at <http://www.muflone.com/pyodoo/>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyOdoo
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.1
|
|
4
4
|
Summary: API for Odoo
|
|
5
5
|
Author-email: Fabio Castelli <muflone@muflone.com>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -12,11 +12,13 @@ Classifier: Development Status :: 1 - Planning
|
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
19
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
20
|
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Requires-Python: >=3.9
|
|
20
22
|
Description-Content-Type: text/markdown
|
|
21
23
|
License-File: LICENSE
|
|
22
24
|
Requires-Dist: xlrd~=2.0
|
|
@@ -25,7 +27,6 @@ Dynamic: license-file
|
|
|
25
27
|
|
|
26
28
|
# PyOdoo
|
|
27
29
|
|
|
28
|
-
[](https://www.travis-ci.com/github/muflone/pyodoo)
|
|
29
30
|
[](https://circleci.com/gh/muflone/pyodoo)
|
|
30
31
|
[](https://github.com/muflone/pyodoo/actions/workflows/python-3.9.yml)
|
|
31
32
|
[](https://github.com/muflone/pyodoo/actions/workflows/python-3.10.yml)
|
|
@@ -65,3 +66,5 @@ Currently the following implementations are provided:
|
|
|
65
66
|
# Usage
|
|
66
67
|
|
|
67
68
|
Please see the **samples** and the **tests** folders for some usage examples.
|
|
69
|
+
|
|
70
|
+
Examples and documentation is available at <http://www.muflone.com/pyodoo/>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# PyOdoo
|
|
2
2
|
|
|
3
|
-
[](https://www.travis-ci.com/github/muflone/pyodoo)
|
|
4
3
|
[](https://circleci.com/gh/muflone/pyodoo)
|
|
5
4
|
[](https://github.com/muflone/pyodoo/actions/workflows/python-3.9.yml)
|
|
6
5
|
[](https://github.com/muflone/pyodoo/actions/workflows/python-3.10.yml)
|
|
@@ -40,3 +39,5 @@ Currently the following implementations are provided:
|
|
|
40
39
|
# Usage
|
|
41
40
|
|
|
42
41
|
Please see the **samples** and the **tests** folders for some usage examples.
|
|
42
|
+
|
|
43
|
+
Examples and documentation is available at <http://www.muflone.com/pyodoo/>
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
##
|
|
20
20
|
|
|
21
21
|
from typing import Any, Optional, Union
|
|
22
|
+
import urllib.parse
|
|
22
23
|
from xmlrpc.client import ServerProxy
|
|
23
24
|
|
|
24
25
|
import requests
|
|
@@ -27,6 +28,7 @@ import requests.auth
|
|
|
27
28
|
from .boolean_operator import BooleanOperator
|
|
28
29
|
from .filter import Filter
|
|
29
30
|
from .implementation import Implementation
|
|
31
|
+
from .transport import TimeoutHttpTransport, TimeoutHttpsTransport
|
|
30
32
|
|
|
31
33
|
|
|
32
34
|
class Api(object):
|
|
@@ -53,6 +55,7 @@ class Api(object):
|
|
|
53
55
|
self.language = language
|
|
54
56
|
self.uid = None
|
|
55
57
|
self.implementation = implementation
|
|
58
|
+
self.timeout = None
|
|
56
59
|
# Remove trailing / from endpoint
|
|
57
60
|
if self.endpoint.endswith('/'):
|
|
58
61
|
self.endpoint = self.endpoint[:-1]
|
|
@@ -76,21 +79,25 @@ class Api(object):
|
|
|
76
79
|
{})
|
|
77
80
|
elif self.implementation == Implementation.JSONRPC:
|
|
78
81
|
# Authentication for JSON-RPC
|
|
79
|
-
self.session.auth = requests.auth.HTTPBasicAuth(
|
|
80
|
-
username=self.username,
|
|
81
|
-
password=self.password)
|
|
82
82
|
response = self.session.post(
|
|
83
|
-
url=self.build_endpoint('
|
|
83
|
+
url=self.build_endpoint(method='jsonrpc'),
|
|
84
84
|
json={
|
|
85
85
|
'jsonrpc': '2.0',
|
|
86
|
+
'method': 'call',
|
|
86
87
|
'params': {
|
|
87
|
-
'
|
|
88
|
-
'
|
|
89
|
-
'
|
|
88
|
+
'service': 'common',
|
|
89
|
+
'method': 'authenticate',
|
|
90
|
+
'args': [
|
|
91
|
+
self.database,
|
|
92
|
+
self.username,
|
|
93
|
+
self.password,
|
|
94
|
+
{}
|
|
95
|
+
]
|
|
90
96
|
}
|
|
91
|
-
}
|
|
97
|
+
},
|
|
98
|
+
timeout=self.timeout)
|
|
92
99
|
result = response.json() if response else None
|
|
93
|
-
self.uid = result['result']
|
|
100
|
+
self.uid = result['result'] if result else None
|
|
94
101
|
else:
|
|
95
102
|
# Invalid implementation
|
|
96
103
|
raise ValueError(f'Invalid implementation {self.implementation}')
|
|
@@ -117,7 +124,22 @@ class Api(object):
|
|
|
117
124
|
:param method: The name of the method to execute
|
|
118
125
|
:return: A new ServerProxy object
|
|
119
126
|
"""
|
|
120
|
-
|
|
127
|
+
url = self.build_endpoint(method=method)
|
|
128
|
+
scheme = urllib.parse.urlparse(url=url).scheme.lower()
|
|
129
|
+
if self.timeout is not None and scheme == 'https':
|
|
130
|
+
# Return a ServerProxy object using TimeoutHttpsTransport
|
|
131
|
+
result = ServerProxy(
|
|
132
|
+
uri=url,
|
|
133
|
+
transport=TimeoutHttpsTransport(timeout=self.timeout))
|
|
134
|
+
elif self.timeout is not None and scheme == 'http':
|
|
135
|
+
# Return a ServerProxy object using TimeoutHttpTransport
|
|
136
|
+
result = ServerProxy(
|
|
137
|
+
uri=url,
|
|
138
|
+
transport=TimeoutHttpTransport(timeout=self.timeout))
|
|
139
|
+
else:
|
|
140
|
+
# Return the standard ServerProxy object without any transport
|
|
141
|
+
result = ServerProxy(uri=url)
|
|
142
|
+
return result
|
|
121
143
|
|
|
122
144
|
def get_proxy_object(self
|
|
123
145
|
) -> ServerProxy:
|
|
@@ -184,7 +206,8 @@ class Api(object):
|
|
|
184
206
|
kwargs
|
|
185
207
|
],
|
|
186
208
|
}
|
|
187
|
-
}
|
|
209
|
+
},
|
|
210
|
+
timeout=self.timeout
|
|
188
211
|
).json().get('result')
|
|
189
212
|
else:
|
|
190
213
|
# Invalid implementation
|
|
@@ -368,3 +391,13 @@ class Api(object):
|
|
|
368
391
|
return self.do_execute(method_name='message_post',
|
|
369
392
|
args=[entity_id],
|
|
370
393
|
kwargs=kwargs)
|
|
394
|
+
|
|
395
|
+
def set_timeout(self,
|
|
396
|
+
timeout: Optional[float]) -> None:
|
|
397
|
+
"""
|
|
398
|
+
Set the connection and transfer timeout
|
|
399
|
+
|
|
400
|
+
:param timeout: allowed time for connection and transfer in seconds
|
|
401
|
+
:return: None
|
|
402
|
+
"""
|
|
403
|
+
self.timeout = timeout
|
|
@@ -263,6 +263,9 @@ class Model(object):
|
|
|
263
263
|
language=self.api.language,
|
|
264
264
|
authenticate=authenticate,
|
|
265
265
|
implementation=self.api.implementation)
|
|
266
|
+
# Use the same timeout
|
|
267
|
+
if self.api.timeout is not None:
|
|
268
|
+
model.api.set_timeout(timeout=self.api.timeout)
|
|
266
269
|
if not authenticate and use_existing_uid:
|
|
267
270
|
# Use the existing UID
|
|
268
271
|
model.api.uid = self.api.uid
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Project: PyOdoo
|
|
3
|
+
# Description: API for Odoo
|
|
4
|
+
# Author: Fabio Castelli (Muflone) <muflone@muflone.com>
|
|
5
|
+
# Copyright: 2021-2026 Fabio Castelli
|
|
6
|
+
# License: GPL-3+
|
|
7
|
+
# This program is free software: you can redistribute it and/or modify
|
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
10
|
+
# (at your option) any later version.
|
|
11
|
+
#
|
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
# GNU General Public License for more details.
|
|
16
|
+
#
|
|
17
|
+
# You should have received a copy of the GNU General Public License
|
|
18
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
19
|
+
##
|
|
20
|
+
|
|
21
|
+
from typing import Any
|
|
22
|
+
from xmlrpc.client import SafeTransport, Transport
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TimeoutHttpTransport(Transport):
|
|
26
|
+
"""
|
|
27
|
+
XML-RPC transport with configurable timeout for HTTP endpoints.
|
|
28
|
+
"""
|
|
29
|
+
def __init__(self,
|
|
30
|
+
timeout: float,
|
|
31
|
+
*args: Any,
|
|
32
|
+
**kwargs: Any
|
|
33
|
+
) -> None:
|
|
34
|
+
super().__init__(*args, **kwargs)
|
|
35
|
+
self.timeout = timeout
|
|
36
|
+
|
|
37
|
+
def make_connection(self,
|
|
38
|
+
host: str
|
|
39
|
+
) -> Any:
|
|
40
|
+
"""
|
|
41
|
+
Custom make_connection method to set the socket timeout
|
|
42
|
+
|
|
43
|
+
:param host: destination host
|
|
44
|
+
:return: connection object
|
|
45
|
+
"""
|
|
46
|
+
connection = super().make_connection(host=host)
|
|
47
|
+
connection.timeout = self.timeout
|
|
48
|
+
if connection.sock:
|
|
49
|
+
connection.sock.settimeout(self.timeout)
|
|
50
|
+
return connection
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class TimeoutHttpsTransport(SafeTransport):
|
|
54
|
+
"""
|
|
55
|
+
XML-RPC transport with configurable timeout for HTTPS endpoints.
|
|
56
|
+
"""
|
|
57
|
+
def __init__(self,
|
|
58
|
+
timeout: float,
|
|
59
|
+
*args: Any,
|
|
60
|
+
**kwargs: Any
|
|
61
|
+
) -> None:
|
|
62
|
+
super().__init__(*args, **kwargs)
|
|
63
|
+
self.timeout = timeout
|
|
64
|
+
|
|
65
|
+
def make_connection(self,
|
|
66
|
+
host: str
|
|
67
|
+
) -> Any:
|
|
68
|
+
"""
|
|
69
|
+
Custom make_connection method to set the socket timeout
|
|
70
|
+
|
|
71
|
+
:param host: destination host
|
|
72
|
+
:return: connection object
|
|
73
|
+
"""
|
|
74
|
+
connection = super().make_connection(host=host)
|
|
75
|
+
connection.timeout = self.timeout
|
|
76
|
+
if connection.sock:
|
|
77
|
+
connection.sock.settimeout(self.timeout)
|
|
78
|
+
return connection
|
|
@@ -12,6 +12,7 @@ authors = [
|
|
|
12
12
|
license = 'GPL-3.0-or-later'
|
|
13
13
|
license-files = ['LICENSE']
|
|
14
14
|
dynamic = ['version']
|
|
15
|
+
requires-python = '>=3.9'
|
|
15
16
|
dependencies = [
|
|
16
17
|
'xlrd~=2.0',
|
|
17
18
|
'requests~=2.32',
|
|
@@ -21,6 +22,7 @@ classifiers = [
|
|
|
21
22
|
'Intended Audience :: Developers',
|
|
22
23
|
'Operating System :: OS Independent',
|
|
23
24
|
'Programming Language :: Python :: 3',
|
|
25
|
+
'Programming Language :: Python :: 3.9',
|
|
24
26
|
'Programming Language :: Python :: 3.10',
|
|
25
27
|
'Programming Language :: Python :: 3.11',
|
|
26
28
|
'Programming Language :: Python :: 3.12',
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|