Skip to content

Commit 355c45c

Browse files
[Tables] on a 413 throw a RequestEntity Too Large Error (Azure#18181)
Azure#18172
1 parent 8b34155 commit 355c45c

File tree

10 files changed

+155
-25
lines changed

10 files changed

+155
-25
lines changed

sdk/tables/azure-data-tables/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* Removed unused legacy client-side encryption attributes from client classes.
1616
* Fixed sharing of pipeline between service/table clients.
1717
* Added support for Azurite storage emulator
18+
* Throws a `RequestTooLargeError` on batch requests that return a 413 error code
1819

1920
## 12.0.0b6 (2021-04-06)
2021
* Updated deserialization of datetime fields in entities to support preservation of the service format with additional decimal place.

sdk/tables/azure-data-tables/azure/data/tables/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from azure.data.tables._models import TableServiceStats
77

88
from ._entity import TableEntity, EntityProperty, EdmType
9+
from ._error import RequestTooLargeError
910
from ._table_shared_access_signature import generate_table_sas, generate_account_sas
1011
from ._table_client import TableClient
1112
from ._table_service_client import TableServiceClient
@@ -54,4 +55,5 @@
5455
"SASProtocol",
5556
"TableBatchOperations",
5657
"BatchErrorException",
58+
"RequestTooLargeError",
5759
]

sdk/tables/azure-data-tables/azure/data/tables/_base_client.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
STORAGE_OAUTH_SCOPE,
4242
SERVICE_HOST_BASE,
4343
)
44+
from ._error import RequestTooLargeError
4445
from ._models import LocationMode
4546
from ._authentication import SharedKeyCredentialPolicy
4647
from ._policies import (
@@ -306,6 +307,10 @@ def _batch_send(
306307
raise ResourceNotFoundError(
307308
message="The resource could not be found", response=response
308309
)
310+
if response.status_code == 413:
311+
raise RequestTooLargeError(
312+
message="The request was too large", response=response
313+
)
309314
if response.status_code != 202:
310315
raise BatchErrorException(
311316
message="There is a failure in the batch operation.",
@@ -319,6 +324,10 @@ def _batch_send(
319324
raise ResourceNotFoundError(
320325
message="The resource could not be found", response=response
321326
)
327+
if any(p for p in parts if p.status_code == 413):
328+
raise RequestTooLargeError(
329+
message="The request was too large", response=response
330+
)
322331

323332
raise BatchErrorException(
324333
message="There is a failure in the batch operation.",

sdk/tables/azure-data-tables/azure/data/tables/_error.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ def _process_table_error(storage_error):
141141
raise error
142142

143143

144+
class RequestTooLargeError(HttpResponseError):
145+
"""An error response with status code 413 - Request Entity Too Large"""
146+
147+
144148
class TableErrorCode(str, Enum):
145149
# Generic storage values
146150
account_already_exists = "AccountAlreadyExists"

sdk/tables/azure-data-tables/azure/data/tables/_models.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -523,19 +523,19 @@ class SASProtocol(str, Enum):
523523
HTTP = "http"
524524

525525

526-
class PartialBatchErrorException(HttpResponseError):
527-
"""There is a partial failure in batch operations.
528-
529-
:param str message: The message of the exception.
530-
:param response: Server response to be deserialized.
531-
:param list parts: A list of the parts in multipart response.
532-
"""
533-
534-
def __init__(self, message, response, parts):
535-
self.parts = parts
536-
super(PartialBatchErrorException, self).__init__(
537-
message=message, response=response
538-
)
526+
# class PartialBatchErrorException(HttpResponseError):
527+
# """There is a partial failure in batch operations.
528+
529+
# :param str message: The message of the exception.
530+
# :param response: Server response to be deserialized.
531+
# :param list parts: A list of the parts in multipart response.
532+
# """
533+
534+
# def __init__(self, message, response, parts):
535+
# self.parts = parts
536+
# super(PartialBatchErrorException, self).__init__(
537+
# message=message, response=response
538+
# )
539539

540540

541541
class BatchErrorException(HttpResponseError):

sdk/tables/azure-data-tables/azure/data/tables/aio/_base_client_async.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from .._base_client import AccountHostsMixin, get_api_version, extract_batch_part_metadata
3232
from .._authentication import SharedKeyCredentialPolicy
3333
from .._constants import STORAGE_OAUTH_SCOPE
34+
from .._error import RequestTooLargeError
3435
from .._models import BatchErrorException
3536
from .._policies import StorageHosts, StorageHeadersPolicy
3637
from .._sdk_moniker import SDK_MONIKER
@@ -141,6 +142,10 @@ async def _batch_send(
141142
raise ResourceNotFoundError(
142143
message="The resource could not be found", response=response
143144
)
145+
if response.status_code == 413:
146+
raise RequestTooLargeError(
147+
message="The request was too large", response=response
148+
)
144149
if response.status_code != 202:
145150
raise BatchErrorException(
146151
message="There is a failure in the batch operation.",
@@ -157,6 +162,11 @@ async def _batch_send(
157162
raise ResourceNotFoundError(
158163
message="The resource could not be found", response=response
159164
)
165+
if any(p for p in parts if p.status_code == 413):
166+
raise RequestTooLargeError(
167+
message="The request was too large", response=response
168+
)
169+
160170

161171
raise BatchErrorException(
162172
message="There is a failure in the batch operation.",

sdk/tables/azure-data-tables/tests/test_table_batch.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from datetime import datetime, timedelta
1212
from dateutil.tz import tzutc
13+
import os
1314
import sys
1415
import uuid
1516

@@ -20,7 +21,6 @@
2021
from azure.core.exceptions import (
2122
ResourceExistsError,
2223
ResourceNotFoundError,
23-
HttpResponseError,
2424
ClientAuthenticationError
2525
)
2626
from azure.data.tables import (
@@ -34,7 +34,7 @@
3434
UpdateMode,
3535
generate_table_sas,
3636
TableSasPermissions,
37-
TableClient
37+
RequestTooLargeError
3838
)
3939

4040
from _shared.testcase import TableTestCase
@@ -870,6 +870,31 @@ def test_batch_sas_auth(self, tables_storage_account_name, tables_primary_storag
870870
finally:
871871
self._tear_down()
872872

873+
@pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
874+
@pytest.mark.live_test_only # Request bodies are very large
875+
@TablesPreparer()
876+
def test_batch_request_too_large(self, tables_storage_account_name, tables_primary_storage_account_key):
877+
# Arrange
878+
self._set_up(tables_storage_account_name, tables_primary_storage_account_key)
879+
try:
880+
881+
batch = self.table.create_batch()
882+
entity = {
883+
'PartitionKey': 'pk001',
884+
'Foo': os.urandom(1024*64),
885+
'Bar': os.urandom(1024*64),
886+
'Baz': os.urandom(1024*64)
887+
}
888+
for i in range(50):
889+
entity['RowKey'] = str(i)
890+
batch.create_entity(entity)
891+
892+
with pytest.raises(RequestTooLargeError):
893+
self.table.send_batch(batch)
894+
895+
finally:
896+
self._tear_down()
897+
873898

874899

875900
class TestTableUnitTest(TableTestCase):

sdk/tables/azure-data-tables/tests/test_table_batch_async.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88

99
import pytest
1010

11-
import uuid
1211
from datetime import datetime, timedelta
1312
from dateutil.tz import tzutc
13+
import os
1414
import sys
15+
import uuid
1516

1617
from devtools_testutils import AzureTestCase
1718

@@ -31,7 +32,8 @@
3132
EdmType,
3233
BatchErrorException,
3334
generate_table_sas,
34-
TableSasPermissions
35+
TableSasPermissions,
36+
RequestTooLargeError
3537
)
3638

3739
from _shared.asynctestcase import AsyncTableTestCase
@@ -760,4 +762,30 @@ async def test_batch_sas_auth(self, tables_storage_account_name, tables_primary_
760762

761763
assert total_entities == transaction_count
762764
finally:
763-
await self._tear_down()
765+
await self._tear_down()
766+
767+
@pytest.mark.live_test_only # Request bodies are very large
768+
@TablesPreparer()
769+
async def test_batch_request_too_large(self, tables_storage_account_name, tables_primary_storage_account_key):
770+
# Arrange
771+
await self._set_up(tables_storage_account_name, tables_primary_storage_account_key)
772+
from azure.data.tables import RequestTooLargeError
773+
try:
774+
775+
batch = self.table.create_batch()
776+
entity = {
777+
'PartitionKey': 'pk001',
778+
'Foo': os.urandom(1024*64),
779+
'Bar': os.urandom(1024*64),
780+
'Baz': os.urandom(1024*64)
781+
}
782+
for i in range(50):
783+
entity['RowKey'] = str(i)
784+
batch.create_entity(entity)
785+
786+
with pytest.raises(RequestTooLargeError):
787+
await self.table.send_batch(batch)
788+
789+
finally:
790+
await self._tear_down()
791+

sdk/tables/azure-data-tables/tests/test_table_batch_cosmos.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
# --------------------------------------------------------------------------
88
from datetime import datetime
99
from dateutil.tz import tzutc
10+
import os
1011
import sys
11-
from time import sleep
1212
import uuid
1313

1414
import pytest
@@ -19,8 +19,6 @@
1919
from azure.core.exceptions import (
2020
ResourceExistsError,
2121
ResourceNotFoundError,
22-
HttpResponseError,
23-
ClientAuthenticationError
2422
)
2523
from azure.data.tables import (
2624
EdmType,
@@ -30,7 +28,9 @@
3028
BatchErrorException,
3129
TableServiceClient,
3230
TableEntity,
33-
UpdateMode
31+
UpdateMode,
32+
33+
RequestTooLargeError
3434
)
3535

3636
from _shared.testcase import TableTestCase, SLEEP_DELAY
@@ -66,7 +66,7 @@ def _tear_down(self):
6666
self.ts.delete_table(table_name)
6767
except:
6868
pass
69-
sleep(SLEEP_DELAY)
69+
self.sleep(SLEEP_DELAY)
7070

7171
#--Helpers-----------------------------------------------------------------
7272

@@ -607,3 +607,28 @@ def test_new_delete_nonexistent_entity(self, tables_cosmos_account_name, tables_
607607

608608
finally:
609609
self._tear_down()
610+
611+
@pytest.mark.skipif(sys.version_info < (3, 0), reason="requires Python3")
612+
@pytest.mark.live_test_only # Request bodies are very large
613+
@CosmosPreparer()
614+
def test_batch_request_too_large(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
615+
# Arrange
616+
self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
617+
try:
618+
619+
batch = self.table.create_batch()
620+
entity = {
621+
'PartitionKey': 'pk001',
622+
'Foo': os.urandom(1024*64),
623+
'Bar': os.urandom(1024*64),
624+
'Baz': os.urandom(1024*64)
625+
}
626+
for i in range(20):
627+
entity['RowKey'] = str(i)
628+
batch.create_entity(entity)
629+
630+
with pytest.raises(RequestTooLargeError):
631+
self.table.send_batch(batch)
632+
633+
finally:
634+
self._tear_down()

sdk/tables/azure-data-tables/tests/test_table_batch_cosmos_async.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99
from datetime import datetime
1010
from dateutil.tz import tzutc
11+
import os
1112
import sys
12-
from time import sleep
1313
import uuid
1414

1515
import pytest
@@ -28,7 +28,8 @@
2828
UpdateMode,
2929
EntityProperty,
3030
EdmType,
31-
BatchErrorException
31+
BatchErrorException,
32+
RequestTooLargeError
3233
)
3334
from azure.data.tables.aio import TableServiceClient
3435

@@ -666,3 +667,28 @@ async def test_new_delete_nonexistent_entity(self, tables_cosmos_account_name, t
666667

667668
finally:
668669
await self._tear_down()
670+
671+
@pytest.mark.live_test_only # Request bodies are very large
672+
@CosmosPreparer()
673+
async def test_batch_request_too_large(self, tables_cosmos_account_name, tables_primary_cosmos_account_key):
674+
# Arrange
675+
await self._set_up(tables_cosmos_account_name, tables_primary_cosmos_account_key)
676+
try:
677+
678+
batch = self.table.create_batch()
679+
entity = {
680+
'PartitionKey': 'pk001',
681+
'Foo': os.urandom(1024*64),
682+
'Bar': os.urandom(1024*64),
683+
'Baz': os.urandom(1024*64)
684+
}
685+
for i in range(20):
686+
entity['RowKey'] = str(i)
687+
batch.create_entity(entity)
688+
689+
with pytest.raises(RequestTooLargeError):
690+
await self.table.send_batch(batch)
691+
692+
finally:
693+
await self._tear_down()
694+

0 commit comments

Comments
 (0)