Skip to content

Commit 31df878

Browse files
SG-36677 Optimize payload by prevent unnecessary data (#360)
* Optimize payload by prevent unnecessary data * Packaging for pre-release * Code review improvements * Improve example * Improve example * Process env var * Format documentation code * Swap env var logic * Restrict env var values * Remove lowercase transform * Read env var once * Add unit tests * Packaging for v3.7.0
1 parent d0b5b50 commit 31df878

File tree

5 files changed

+124
-11
lines changed

5 files changed

+124
-11
lines changed

HISTORY.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ Flow Production Tracking Python API Changelog
44

55
Here you can see the full list of changes between each Python API release.
66

7+
v3.7.0 (2024 Dec 9)
8+
===========================
9+
- Remove unnecessary data in the payload when combining related queries before sending it to the server.
10+
This would improve overall performance decreasing network latency and server processing.
11+
See documentation for more information.
12+
13+
714
v3.6.2 (2024 Aug 13)
815
====================
916
- Remove Ticket entity reference and prepare this to run in CI.

docs/reference.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,36 @@ Stores the number of milliseconds to wait between request retries. By default,
949949

950950
In the case that both this environment variable and the config's ``rpc_attempt_interval`` property are set, the value in ``rpc_attempt_interal`` will be used.
951951

952+
953+
SHOTGUN_API_ENABLE_ENTITY_OPTIMIZATION
954+
=======================================
955+
956+
.. note:: (v3.7.0) This is an experimental feature. Feel free to disable this feature if you are experiencing any issues.
957+
958+
When set to ``1``, this environment variable will enable the entity optimization feature.
959+
This feature is disabled by default and is used to reduce the payload size made to the server when retrieving entities
960+
improving overall performance by decreasing network latency and server processing.
961+
962+
For example, a ``find`` call like this:
963+
964+
.. code-block:: python
965+
966+
sg.find('Asset', [['project', 'is', {
967+
'created_at': datetime.datetime(2015, 12, 16, 11, 2, 10, tzinfo),
968+
'id': 9999,
969+
'name': 'Demo: Game',
970+
'type': 'Project',
971+
# More entity attributes
972+
}]])
973+
974+
975+
Will internally be transformed as if you invoked something like this:
976+
977+
.. code-block:: python
978+
979+
sg.find('Asset', [['project', 'is', {'id': 999, 'type': 'Project'}]])
980+
981+
952982
************
953983
Localization
954984
************

setup.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,17 @@
1818
f = open('LICENSE')
1919
license = f.read().strip()
2020

21-
# For python 2.4 support
22-
script_args = sys.argv[1:]
23-
if (sys.version_info[0] <= 2) or (sys.version_info[0] == 2 and sys.version_info[1] <= 5):
24-
if 'install' in script_args and '--no-compile' not in script_args:
25-
script_args.append('--no-compile')
26-
27-
2821
setup(
2922
name='shotgun_api3',
30-
version='3.6.2',
23+
version='3.7.0',
3124
description='Flow Production Tracking Python API',
3225
long_description=readme,
3326
author='Autodesk',
3427
author_email='https://www.autodesk.com/support/contact-support',
3528
url='https://github.com/shotgunsoftware/python-api',
3629
license=license,
3730
packages=find_packages(exclude=('tests',)),
38-
script_args=script_args,
31+
script_args=sys.argv[1:],
3932
include_package_data=True,
4033
package_data={'': ['cacerts.txt', 'cacert.pem']},
4134
zip_safe=False,

shotgun_api3/shotgun.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ def _is_mimetypes_broken():
105105

106106
SG_TIMEZONE = SgTimezone()
107107

108+
SHOTGUN_API_ENABLE_ENTITY_OPTIMIZATION = False
109+
108110
NO_SSL_VALIDATION = False
109111
"""
110112
Turns off hostname matching validation for SSL certificates
@@ -116,7 +118,7 @@ def _is_mimetypes_broken():
116118

117119
# ----------------------------------------------------------------------------
118120
# Version
119-
__version__ = "3.6.2"
121+
__version__ = "3.7.0"
120122

121123
# ----------------------------------------------------------------------------
122124
# Errors
@@ -649,7 +651,11 @@ def __init__(self,
649651
if self.config.rpc_attempt_interval < 0:
650652
raise ValueError("Value of SHOTGUN_API_RETRY_INTERVAL must be positive, "
651653
"got '%s'." % self.config.rpc_attempt_interval)
652-
654+
655+
global SHOTGUN_API_ENABLE_ENTITY_OPTIMIZATION
656+
if os.environ.get("SHOTGUN_API_ENABLE_ENTITY_OPTIMIZATION", "0").strip().lower() == "1":
657+
SHOTGUN_API_ENABLE_ENTITY_OPTIMIZATION = True
658+
653659
self._connection = None
654660

655661
self.__ca_certs = self._get_certs_file(ca_certs)
@@ -4470,6 +4476,25 @@ def _translate_filters_simple(sg_filter):
44704476
if len(values) == 1 and isinstance(values[0], (list, tuple)):
44714477
values = values[0]
44724478

4479+
# Payload optimization: Do not send a full object
4480+
# just send the `type` and `id` when combining related queries
4481+
global SHOTGUN_API_ENABLE_ENTITY_OPTIMIZATION
4482+
if (
4483+
SHOTGUN_API_ENABLE_ENTITY_OPTIMIZATION
4484+
and condition["path"] != "id"
4485+
and condition["relation"] in ["is", "is_not"]
4486+
and isinstance(values[0], dict)
4487+
):
4488+
try:
4489+
values = [
4490+
{
4491+
"type": values[0]["type"],
4492+
"id": values[0]["id"],
4493+
}
4494+
]
4495+
except KeyError:
4496+
pass
4497+
44734498
condition["values"] = values
44744499

44754500
return condition

tests/test_unit.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,63 @@ def test_invalid(self):
405405

406406
self.assertRaises(api.ShotgunError, api.shotgun._translate_filters, filters, "all")
407407

408+
def test_related_object(self):
409+
filters = [
410+
[
411+
"project",
412+
"is",
413+
{"foo": "foo", "bar": "bar", "id": 999, "baz": "baz", "type": "Anything"},
414+
],
415+
]
416+
expected = {
417+
"logical_operator": "and",
418+
"conditions": [
419+
{
420+
"path": "project",
421+
"relation": "is",
422+
"values": [
423+
{
424+
"foo": "foo",
425+
"bar": "bar",
426+
"baz": "baz",
427+
"id": 999,
428+
"type": "Anything",
429+
}
430+
],
431+
}
432+
],
433+
}
434+
result = api.shotgun._translate_filters(filters, "all")
435+
self.assertEqual(result, expected)
436+
437+
def test_related_object_entity_optimization(self):
438+
filters = [
439+
[
440+
"project",
441+
"is",
442+
{"foo": "foo", "bar": "bar", "id": 999, "baz": "baz", "type": "Anything"},
443+
],
444+
]
445+
expected = {
446+
"logical_operator": "and",
447+
"conditions": [
448+
{
449+
"path": "project",
450+
"relation": "is",
451+
"values": [
452+
{
453+
"id": 999,
454+
"type": "Anything",
455+
}
456+
],
457+
}
458+
],
459+
}
460+
os.environ["SHOTGUN_API_ENABLE_ENTITY_OPTIMIZATION"] = "1"
461+
api.Shotgun("http://server_path", "script_name", "api_key", connect=False)
462+
result = api.shotgun._translate_filters(filters, "all")
463+
self.assertEqual(result, expected)
464+
408465

409466
class TestCerts(unittest.TestCase):
410467
# A dummy bad url provided by Amazon
@@ -506,5 +563,6 @@ def _test_mimetypes_import(self, platform, major, minor, patch_number, result, m
506563
mock.platform = platform
507564
self.assertEqual(_is_mimetypes_broken(), result)
508565

566+
509567
if __name__ == '__main__':
510568
unittest.main()

0 commit comments

Comments
 (0)