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.
Files changed (29) hide show
  1. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/PKG-INFO +2 -10
  2. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/README.md +1 -9
  3. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/pyproject.toml +17 -17
  4. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/api.py +98 -14
  5. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/core.py +377 -15
  6. salespyforce-1.4.0rc0/src/salespyforce/decorators.py +53 -0
  7. salespyforce-1.4.0rc0/src/salespyforce/errors/handlers.py +53 -0
  8. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/knowledge.py +28 -5
  9. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/core_utils.py +86 -2
  10. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/log_utils.py +7 -7
  11. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/test_core_utils.py +40 -1
  12. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/test_log_utils.py +2 -2
  13. salespyforce-1.4.0.dev1/src/salespyforce/errors/handlers.py +0 -15
  14. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/LICENSE +0 -0
  15. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/__init__.py +0 -0
  16. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/chatter.py +0 -0
  17. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/errors/__init__.py +0 -0
  18. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/errors/exceptions.py +0 -0
  19. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/__init__.py +0 -0
  20. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/helper.py +0 -0
  21. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/__init__.py +0 -0
  22. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/conftest.py +0 -0
  23. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/resources.py +0 -0
  24. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/test_instantiate_object.py +0 -0
  25. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/test_sobjects.py +0 -0
  26. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/test_soql.py +0 -0
  27. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/test_sosl.py +0 -0
  28. {salespyforce-1.4.0.dev1 → salespyforce-1.4.0rc0}/src/salespyforce/utils/tests/test_version_utils.py +0 -0
  29. {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.0.dev1
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.dev1-blue">
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.dev1-blue">
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.dev1"
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
- { name = "Jeff Shurtliff", email = "jeffshurtliff@gmail.com" }
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
- "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"
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
- "PyYAML>=6.0.3,<7",
30
- "requests>=2.32.5",
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
- { include = "salespyforce", from = "src" }
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: 17 Feb 2023
7
+ :Modified Date: 30 Jan 2026
8
8
  """
9
9
 
10
10
  import requests
11
11
 
12
- from .utils import log_utils
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
- # Make sure the endpoint begins with a slash
44
- endpoint = f'/{endpoint}' if not endpoint.startswith('/') else endpoint
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(f'{sfdc_object.instance_url}{endpoint}', headers=headers, params=params, timeout=timeout)
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
- # Make sure the endpoint begins with a slash
90
- endpoint = f'/{endpoint}' if not endpoint.startswith('/') else endpoint
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(f'{sfdc_object.instance_url}{endpoint}', json=payload, headers=headers, params=params,
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(f'{sfdc_object.instance_url}{endpoint}', json=payload, headers=headers, params=params,
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(f'{sfdc_object.instance_url}{endpoint}', json=payload, headers=headers, params=params,
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 OR PUT) must be defined.')
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