salespyforce 1.4.0.dev1__tar.gz → 1.4.0rc0__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.
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/PKG-INFO +2 -10
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/README.md +1 -9
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/pyproject.toml +17 -17
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/api.py +98 -14
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/core.py +377 -15
- salespyforce-1.4.0rc0/src/salespyforce/decorators.py +53 -0
- salespyforce-1.4.0rc0/src/salespyforce/errors/handlers.py +53 -0
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/knowledge.py +28 -5
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/core_utils.py +86 -2
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/log_utils.py +7 -7
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/test_core_utils.py +40 -1
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/test_log_utils.py +2 -2
- salespyforce-1.4.0.dev1/src/salespyforce/errors/handlers.py +0 -15
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/LICENSE +0 -0
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/__init__.py +0 -0
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/chatter.py +0 -0
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/errors/__init__.py +0 -0
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/errors/exceptions.py +0 -0
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/__init__.py +0 -0
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/helper.py +0 -0
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/__init__.py +0 -0
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/conftest.py +0 -0
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/resources.py +0 -0
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/test_instantiate_object.py +0 -0
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/test_sobjects.py +0 -0
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/test_soql.py +0 -0
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/test_sosl.py +0 -0
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/test_version_utils.py +0 -0
- {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: salespyforce
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.0rc0
|
|
4
4
|
Summary: A Python toolset for performing Salesforce API calls
|
|
5
5
|
License: MIT License
|
|
6
6
|
|
|
@@ -63,7 +63,7 @@ A Python toolset for performing Salesforce API calls
|
|
|
63
63
|
<td>Latest Beta/RC Release</td>
|
|
64
64
|
<td>
|
|
65
65
|
<a href='https://pypi.org/project/salespyforce/#history'>
|
|
66
|
-
<img alt="PyPI" src="https://img.shields.io/badge/pypi-1.4.0.
|
|
66
|
+
<img alt="PyPI" src="https://img.shields.io/badge/pypi-1.4.0.dev2-blue">
|
|
67
67
|
</a>
|
|
68
68
|
</td>
|
|
69
69
|
</tr>
|
|
@@ -151,14 +151,6 @@ The package can be installed via pip using the syntax below.
|
|
|
151
151
|
pip install salespyforce --upgrade
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
-
You may also clone the repository and install from source using below.
|
|
155
|
-
|
|
156
|
-
```sh
|
|
157
|
-
git clone git://github.com/jeffshurtliff/salespyforce.git
|
|
158
|
-
cd salespyforce/
|
|
159
|
-
python setup.py install
|
|
160
|
-
```
|
|
161
|
-
|
|
162
154
|
## Change Log
|
|
163
155
|
The change log can be found in the [documentation](https://salespyforce.readthedocs.io/en/latest/changelog.html).
|
|
164
156
|
|
|
@@ -14,7 +14,7 @@ A Python toolset for performing Salesforce API calls
|
|
|
14
14
|
<td>Latest Beta/RC Release</td>
|
|
15
15
|
<td>
|
|
16
16
|
<a href='https://pypi.org/project/salespyforce/#history'>
|
|
17
|
-
<img alt="PyPI" src="https://img.shields.io/badge/pypi-1.4.0.
|
|
17
|
+
<img alt="PyPI" src="https://img.shields.io/badge/pypi-1.4.0.dev2-blue">
|
|
18
18
|
</a>
|
|
19
19
|
</td>
|
|
20
20
|
</tr>
|
|
@@ -102,14 +102,6 @@ The package can be installed via pip using the syntax below.
|
|
|
102
102
|
pip install salespyforce --upgrade
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
You may also clone the repository and install from source using below.
|
|
106
|
-
|
|
107
|
-
```sh
|
|
108
|
-
git clone git://github.com/jeffshurtliff/salespyforce.git
|
|
109
|
-
cd salespyforce/
|
|
110
|
-
python setup.py install
|
|
111
|
-
```
|
|
112
|
-
|
|
113
105
|
## Change Log
|
|
114
106
|
The change log can be found in the [documentation](https://salespyforce.readthedocs.io/en/latest/changelog.html).
|
|
115
107
|
|
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "salespyforce"
|
|
3
|
-
version = "1.4.0.
|
|
3
|
+
version = "1.4.0.rc0"
|
|
4
4
|
description = "A Python toolset for performing Salesforce API calls"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.9,<4.0"
|
|
7
7
|
license = { file = "LICENSE" }
|
|
8
8
|
authors = [
|
|
9
|
-
|
|
9
|
+
{ name = "Jeff Shurtliff", email = "jeffshurtliff@gmail.com" }
|
|
10
10
|
]
|
|
11
11
|
keywords = ["salesforce", "sfdc", "api", "rest", "tooling", "python"]
|
|
12
12
|
|
|
13
13
|
classifiers = [
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
19
|
+
"Programming Language :: Python :: 3.9",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Topic :: Software Development :: Libraries",
|
|
25
|
+
"Topic :: Internet :: WWW/HTTP"
|
|
26
26
|
]
|
|
27
27
|
|
|
28
28
|
dependencies = [
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
"PyYAML>=6.0.3,<7",
|
|
30
|
+
"requests>=2.32.5",
|
|
31
31
|
]
|
|
32
32
|
|
|
33
33
|
[project.urls]
|
|
@@ -41,7 +41,7 @@ Documentation = "https://salespyforce.readthedocs.io/en/latest/"
|
|
|
41
41
|
# --------------------------------------------------------------------
|
|
42
42
|
[tool.poetry]
|
|
43
43
|
packages = [
|
|
44
|
-
|
|
44
|
+
{ include = "salespyforce", from = "src" }
|
|
45
45
|
]
|
|
46
46
|
|
|
47
47
|
include = ["LICENSE", "README.md"]
|
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
:Synopsis: Defines the basic functions associated with the Salesforce API
|
|
5
5
|
:Created By: Jeff Shurtliff
|
|
6
6
|
:Last Modified: Jeff Shurtliff
|
|
7
|
-
:Modified Date:
|
|
7
|
+
:Modified Date: 30 Jan 2026
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import requests
|
|
11
11
|
|
|
12
|
-
from .
|
|
12
|
+
from . import errors
|
|
13
|
+
from .utils import core_utils, log_utils
|
|
13
14
|
|
|
14
15
|
# Initialize logging
|
|
15
16
|
logger = log_utils.initialize_logging(__name__)
|
|
@@ -19,6 +20,10 @@ def get(sfdc_object, endpoint, params=None, headers=None, timeout=30, show_full_
|
|
|
19
20
|
"""This method performs a GET request against the Salesforce instance.
|
|
20
21
|
(`Reference <https://jereze.com/code/authentification-salesforce-rest-api-python/>`_)
|
|
21
22
|
|
|
23
|
+
.. version-changed:: 1.4.0
|
|
24
|
+
The full URL for the API call is now constructed prior to making the call.
|
|
25
|
+
The provided URL is also now evaluated to ensure it is a valid Salesforce URL.
|
|
26
|
+
|
|
22
27
|
:param sfdc_object: The instantiated SalesPyForce object
|
|
23
28
|
:param endpoint: The API endpoint to query
|
|
24
29
|
:type endpoint: str
|
|
@@ -40,12 +45,13 @@ def get(sfdc_object, endpoint, params=None, headers=None, timeout=30, show_full_
|
|
|
40
45
|
default_headers = _get_headers(sfdc_object.access_token)
|
|
41
46
|
headers = default_headers if not headers else headers
|
|
42
47
|
|
|
43
|
-
#
|
|
44
|
-
|
|
48
|
+
# Construct the request URL
|
|
49
|
+
url = _construct_full_query_url(endpoint, sfdc_object.instance_url)
|
|
45
50
|
|
|
46
51
|
# Perform the API call
|
|
47
|
-
response = requests.get(
|
|
52
|
+
response = requests.get(url, headers=headers, params=params, timeout=timeout)
|
|
48
53
|
if response.status_code >= 300:
|
|
54
|
+
# TODO: Functionalize this segment and figure out how to improve on the approach somehow
|
|
49
55
|
if show_full_error:
|
|
50
56
|
raise RuntimeError(f'The GET request failed with a {response.status_code} status code.\n'
|
|
51
57
|
f'{response.text}')
|
|
@@ -61,6 +67,10 @@ def api_call_with_payload(sfdc_object, method, endpoint, payload, params=None, h
|
|
|
61
67
|
"""This method performs a POST call against the Salesforce instance.
|
|
62
68
|
(`Reference <https://jereze.com/code/authentification-salesforce-rest-api-python/>`_)
|
|
63
69
|
|
|
70
|
+
.. version-changed:: 1.4.0
|
|
71
|
+
The full URL for the API call is now constructed prior to making the call.
|
|
72
|
+
The provided URL is also now evaluated to ensure it is a valid Salesforce URL.
|
|
73
|
+
|
|
64
74
|
:param sfdc_object: The instantiated SalesPyForce object
|
|
65
75
|
:param method: The API method (``post``, ``put``, or ``patch``)
|
|
66
76
|
:type method: str
|
|
@@ -86,25 +96,23 @@ def api_call_with_payload(sfdc_object, method, endpoint, payload, params=None, h
|
|
|
86
96
|
default_headers = _get_headers(sfdc_object.access_token)
|
|
87
97
|
headers = default_headers if not headers else headers
|
|
88
98
|
|
|
89
|
-
#
|
|
90
|
-
|
|
99
|
+
# Construct the request URL
|
|
100
|
+
url = _construct_full_query_url(endpoint, sfdc_object.instance_url)
|
|
91
101
|
|
|
92
102
|
# Perform the API call
|
|
93
103
|
if method.lower() == 'post':
|
|
94
|
-
response = requests.post(
|
|
95
|
-
timeout=timeout)
|
|
104
|
+
response = requests.post(url, json=payload, headers=headers, params=params, timeout=timeout)
|
|
96
105
|
elif method.lower() == 'patch':
|
|
97
|
-
response = requests.patch(
|
|
98
|
-
timeout=timeout)
|
|
106
|
+
response = requests.patch(url, json=payload, headers=headers, params=params, timeout=timeout)
|
|
99
107
|
elif method.lower() == 'put':
|
|
100
|
-
response = requests.put(
|
|
101
|
-
timeout=timeout)
|
|
108
|
+
response = requests.put(url, json=payload, headers=headers, params=params, timeout=timeout)
|
|
102
109
|
else:
|
|
103
|
-
raise ValueError('The API call method (POST or PATCH
|
|
110
|
+
raise ValueError('The API call method (POST or PATCH or PUT) must be defined')
|
|
104
111
|
|
|
105
112
|
# Examine the result
|
|
106
113
|
if response.status_code >= 300:
|
|
107
114
|
if show_full_error:
|
|
115
|
+
# TODO: Functionalize this segment and figure out how to improve on the approach somehow
|
|
108
116
|
raise RuntimeError(f'The POST request failed with a {response.status_code} status code.\n'
|
|
109
117
|
f'{response.text}')
|
|
110
118
|
else:
|
|
@@ -117,6 +125,49 @@ def api_call_with_payload(sfdc_object, method, endpoint, payload, params=None, h
|
|
|
117
125
|
return response
|
|
118
126
|
|
|
119
127
|
|
|
128
|
+
def delete(sfdc_object, endpoint, params=None, headers=None, timeout=30, show_full_error=True, return_json=True):
|
|
129
|
+
"""This method performs a DELETE request against the Salesforce instance.
|
|
130
|
+
|
|
131
|
+
.. version-added:: 1.4.0
|
|
132
|
+
|
|
133
|
+
:param sfdc_object: The instantiated SalesPyForce object
|
|
134
|
+
:param endpoint: The API endpoint to query
|
|
135
|
+
:type endpoint: str
|
|
136
|
+
:param params: The query parameters (where applicable)
|
|
137
|
+
:type params: dict, None
|
|
138
|
+
:param headers: Specific API headers to use when performing the API call
|
|
139
|
+
:type headers: dict, None
|
|
140
|
+
:param timeout: The timeout period in seconds (defaults to ``30``)
|
|
141
|
+
:type timeout: int, str, None
|
|
142
|
+
:param show_full_error: Determines if the full error message should be displayed (defaults to ``True``)
|
|
143
|
+
:type show_full_error: bool
|
|
144
|
+
:param return_json: Determines if the response should be returned in JSON format (defaults to ``True``)
|
|
145
|
+
:returns: The API response in JSON format or as a ``requests`` object
|
|
146
|
+
"""
|
|
147
|
+
# Define the parameters as an empty dictionary if none are provided
|
|
148
|
+
params = {} if params is None else params
|
|
149
|
+
|
|
150
|
+
# Define the headers
|
|
151
|
+
default_headers = _get_headers(sfdc_object.access_token)
|
|
152
|
+
headers = default_headers if not headers else headers
|
|
153
|
+
|
|
154
|
+
# Construct the request URL
|
|
155
|
+
url = _construct_full_query_url(endpoint, sfdc_object.instance_url)
|
|
156
|
+
|
|
157
|
+
# Perform the API call
|
|
158
|
+
response = requests.delete(url, headers=headers, params=params, timeout=timeout)
|
|
159
|
+
if response.status_code >= 300:
|
|
160
|
+
if show_full_error:
|
|
161
|
+
# TODO: Functionalize this segment and figure out how to improve on the approach somehow
|
|
162
|
+
raise RuntimeError(f'The DELETE request failed with a {response.status_code} status code.\n'
|
|
163
|
+
f'{response.text}')
|
|
164
|
+
else:
|
|
165
|
+
raise RuntimeError(f'The DELETE request failed with a {response.status_code} status code.')
|
|
166
|
+
if return_json:
|
|
167
|
+
response = response.json()
|
|
168
|
+
return response
|
|
169
|
+
|
|
170
|
+
|
|
120
171
|
def _get_headers(_access_token, _header_type='default'):
|
|
121
172
|
"""This function returns the appropriate HTTP headers to use for different types of API calls."""
|
|
122
173
|
headers = {
|
|
@@ -127,3 +178,36 @@ def _get_headers(_access_token, _header_type='default'):
|
|
|
127
178
|
if _header_type == 'articles':
|
|
128
179
|
headers['accept-language'] = 'en-US'
|
|
129
180
|
return headers
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _construct_full_query_url(_endpoint: str, _instance_url: str) -> str:
|
|
184
|
+
"""This function constructs the URL to use in an API call to the Salesforce REST API.
|
|
185
|
+
|
|
186
|
+
.. version-added:: 1.4.0
|
|
187
|
+
|
|
188
|
+
:param _endpoint: The endpoint provided when calling an API call method or function
|
|
189
|
+
:type _endpoint: str
|
|
190
|
+
:param _instance_url: The Salesforce instance URL defined when the core object was instantiated
|
|
191
|
+
:type _instance_url: str
|
|
192
|
+
:returns: The fully qualified URL
|
|
193
|
+
:raises: :py:exc:`TypeError`,
|
|
194
|
+
:py:exc:`errors.exceptions.InvalidURLError`
|
|
195
|
+
"""
|
|
196
|
+
# Raise an exception if the endpoint is not a string
|
|
197
|
+
if not isinstance(_endpoint, str):
|
|
198
|
+
exc_msg = 'The provided URL must be a string and a valid Salesforce URL'
|
|
199
|
+
logger.critical(exc_msg)
|
|
200
|
+
raise TypeError(exc_msg)
|
|
201
|
+
|
|
202
|
+
# Construct the URL as needed by prepending the instance URL
|
|
203
|
+
if _endpoint.startswith('https://'):
|
|
204
|
+
# Only permit valid Salesforce URLs
|
|
205
|
+
if not core_utils.is_valid_salesforce_url(_endpoint):
|
|
206
|
+
raise errors.exceptions.InvalidURLError(url=_endpoint)
|
|
207
|
+
_url = _endpoint
|
|
208
|
+
else:
|
|
209
|
+
_endpoint = f'/{_endpoint}' if not _endpoint.startswith('/') else _endpoint
|
|
210
|
+
_url = f'{_instance_url}{_endpoint}'
|
|
211
|
+
|
|
212
|
+
# Return the constructed URL
|
|
213
|
+
return _url
|