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.
Files changed (34) hide show
  1. {pyodoo-0.8.0 → pyodoo-0.8.1}/PKG-INFO +5 -2
  2. {pyodoo-0.8.0 → pyodoo-0.8.1}/PyOdoo.egg-info/PKG-INFO +5 -2
  3. {pyodoo-0.8.0 → pyodoo-0.8.1}/PyOdoo.egg-info/SOURCES.txt +1 -0
  4. {pyodoo-0.8.0 → pyodoo-0.8.1}/README.md +2 -1
  5. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/api.py +44 -11
  6. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/constants.py +1 -1
  7. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/model.py +3 -0
  8. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/samples/contacts.py +1 -0
  9. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/samples/contacts_async.py +1 -0
  10. pyodoo-0.8.1/pyodoo/transport.py +78 -0
  11. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyproject.toml +2 -0
  12. {pyodoo-0.8.0 → pyodoo-0.8.1}/LICENSE +0 -0
  13. {pyodoo-0.8.0 → pyodoo-0.8.1}/PyOdoo.egg-info/dependency_links.txt +0 -0
  14. {pyodoo-0.8.0 → pyodoo-0.8.1}/PyOdoo.egg-info/requires.txt +0 -0
  15. {pyodoo-0.8.0 → pyodoo-0.8.1}/PyOdoo.egg-info/top_level.txt +0 -0
  16. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/__init__.py +0 -0
  17. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/active_status_choice.py +0 -0
  18. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/boolean_operator.py +0 -0
  19. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/compare_type.py +0 -0
  20. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/filter.py +0 -0
  21. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/implementation.py +0 -0
  22. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/message_subtype.py +0 -0
  23. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/python_code.py +0 -0
  24. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/samples/__init__.py +0 -0
  25. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/samples/awaitable.py +0 -0
  26. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/samples/python_code.py +0 -0
  27. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/samples/sql_excel_query.py +0 -0
  28. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/sql_excel_query.py +0 -0
  29. {pyodoo-0.8.0 → pyodoo-0.8.1}/pyodoo/v12/__init__.py +0 -0
  30. {pyodoo-0.8.0 → pyodoo-0.8.1}/setup.cfg +0 -0
  31. {pyodoo-0.8.0 → pyodoo-0.8.1}/tests/test_compare_types.py +0 -0
  32. {pyodoo-0.8.0 → pyodoo-0.8.1}/tests/test_contacts.py +0 -0
  33. {pyodoo-0.8.0 → pyodoo-0.8.1}/tests/test_python_code.py +0 -0
  34. {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.0
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
- [![Travis CI Build Status](https://img.shields.io/travis/com/muflone/pyodoo/master.svg)](https://www.travis-ci.com/github/muflone/pyodoo)
29
30
  [![CircleCI Build Status](https://img.shields.io/circleci/project/github/muflone/pyodoo/master.svg)](https://circleci.com/gh/muflone/pyodoo)
30
31
  [![Python 3.9](https://github.com/muflone/pyodoo/actions/workflows/python-3.9.yml/badge.svg)](https://github.com/muflone/pyodoo/actions/workflows/python-3.9.yml)
31
32
  [![Python 3.10](https://github.com/muflone/pyodoo/actions/workflows/python-3.10.yml/badge.svg)](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.0
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
- [![Travis CI Build Status](https://img.shields.io/travis/com/muflone/pyodoo/master.svg)](https://www.travis-ci.com/github/muflone/pyodoo)
29
30
  [![CircleCI Build Status](https://img.shields.io/circleci/project/github/muflone/pyodoo/master.svg)](https://circleci.com/gh/muflone/pyodoo)
30
31
  [![Python 3.9](https://github.com/muflone/pyodoo/actions/workflows/python-3.9.yml/badge.svg)](https://github.com/muflone/pyodoo/actions/workflows/python-3.9.yml)
31
32
  [![Python 3.10](https://github.com/muflone/pyodoo/actions/workflows/python-3.10.yml/badge.svg)](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/>
@@ -18,6 +18,7 @@ pyodoo/message_subtype.py
18
18
  pyodoo/model.py
19
19
  pyodoo/python_code.py
20
20
  pyodoo/sql_excel_query.py
21
+ pyodoo/transport.py
21
22
  pyodoo/samples/__init__.py
22
23
  pyodoo/samples/awaitable.py
23
24
  pyodoo/samples/contacts.py
@@ -1,6 +1,5 @@
1
1
  # PyOdoo
2
2
 
3
- [![Travis CI Build Status](https://img.shields.io/travis/com/muflone/pyodoo/master.svg)](https://www.travis-ci.com/github/muflone/pyodoo)
4
3
  [![CircleCI Build Status](https://img.shields.io/circleci/project/github/muflone/pyodoo/master.svg)](https://circleci.com/gh/muflone/pyodoo)
5
4
  [![Python 3.9](https://github.com/muflone/pyodoo/actions/workflows/python-3.9.yml/badge.svg)](https://github.com/muflone/pyodoo/actions/workflows/python-3.9.yml)
6
5
  [![Python 3.10](https://github.com/muflone/pyodoo/actions/workflows/python-3.10.yml/badge.svg)](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('web/session/authenticate'),
83
+ url=self.build_endpoint(method='jsonrpc'),
84
84
  json={
85
85
  'jsonrpc': '2.0',
86
+ 'method': 'call',
86
87
  'params': {
87
- 'db': self.database,
88
- 'login': self.username,
89
- 'password': self.password
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']['uid'] if result else None
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
- return ServerProxy(self.build_endpoint(method=method))
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
@@ -19,7 +19,7 @@
19
19
  ##
20
20
 
21
21
  APP_NAME = 'PyOdoo'
22
- APP_VERSION = '0.8.0'
22
+ APP_VERSION = '0.8.1'
23
23
  APP_DESCRIPTION = 'API for Odoo'
24
24
  APP_DOMAIN = 'pyodoo'
25
25
  APP_ID = f'{APP_DOMAIN}.muflone.com'
@@ -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
@@ -36,6 +36,7 @@ model = Model(model_name='res.partner',
36
36
  language=None,
37
37
  authenticate=False,
38
38
  implementation=os.environ['ODOO_RPC_IMPLEMENTATION'])
39
+ model.api.set_timeout(30)
39
40
  # Authenticate user
40
41
  if model.authenticate():
41
42
  print('Authentication successful')
@@ -101,6 +101,7 @@ model = Model(model_name='res.partner',
101
101
  language=None,
102
102
  authenticate=False,
103
103
  implementation=os.environ['ODOO_RPC_IMPLEMENTATION'])
104
+ model.api.set_timeout(30)
104
105
  # Authenticate user
105
106
  model.authenticate()
106
107
  # Change default language
@@ -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