Skip to content
Advertisement

Python TypeError: object is not iterable,

I am kinda new to python and trying to create a DTO that minimizes the amount of properties exposed from my api. I use an Azure table storage to get records and then loop over it to create a smaller object omiting properties. Though somewhere in the process I get: “TypeError: ‘AbbreviatedPackage’ object is not iterable”

In my main I have the follwing call:

@app.get("/list/")
def process_results(request: Request, x_api_key: str = Depends(X_API_KEY)):

    packageClient = QueryClient(az_connection_string, "appstoredev")
    results = packageClient.query_packages_storage("PartitionKey eq 'app'")

    return results

The query_packages_storage()

 def query_packages_storage(self, filter_query):
        from azure.data.tables import TableClient
        table_client = TableClient.from_connection_string(conn_str=self.connection_string, table_name=self.table_name)
        entities = table_client.query_entities(filter_query)

        json_entities = []
        for entity in entities:
            print(entity['ImageUrl'])
            filtered_entity = AbbreviatedPackage(
                entity['ImageUrl'],
                entity['PackageName'],
                entity['DisplayName'],
                entity['Summary']
            )

            json_entities.append(filtered_entity)

        return json.dumps(json_entities)

AbbreviatedPackage class

class AbbreviatedPackage():

    def __init__(self, image_url, package_name, display_name, summary):
        self.imageUrl = image_url
        self.packageName = package_name
        self.displayName = display_name
        self.summary = summary

When I debug the json_entitiesobject gets filled properly enter image description here

Any help would be much sppreciated. Cheers

** Edit

I get the errors while being in the loop enter image description here

INFO:     127.0.0.1:60027 - "GET /list/ HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesuvicornprotocolshttph11_impl.py", line 373, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesuvicornmiddlewareproxy_headers.py", line 75, in __call__
    return await self.app(scope, receive, send)
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesfastapiapplications.py", line 208, in __call__
    await super().__call__(scope, receive, send)
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesstarletteapplications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesstarlettemiddlewareerrors.py", line 181, in __call__
    raise exc
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesstarlettemiddlewareerrors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesstarlettemiddlewarecors.py", line 84, in __call__
    await self.app(scope, receive, send)
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesstarletteexceptions.py", line 82, in __call__
    raise exc
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesstarletteexceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesstarletterouting.py", line 656, in __call__
    await route.handle(scope, receive, send)
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesstarletterouting.py", line 259, in handle
    await self.app(scope, receive, send)
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesstarletterouting.py", line 61, in app
    response = await func(request)
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesfastapirouting.py", line 226, in app
    raw_response = await run_endpoint_function(
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesfastapirouting.py", line 161, in run_endpoint_function
    return await run_in_threadpool(dependant.call, **values)
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesstarletteconcurrency.py", line 39, in run_in_threadpool
    return await anyio.to_thread.run_sync(func, *args)
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesanyioto_thread.py", line 28, in run_sync
    return await get_asynclib().run_sync_in_worker_thread(func, *args, cancellable=cancellable,
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesanyio_backends_asyncio.py", line 805, in run_sync_in_worker_thread
    return await future
  File "C:sourceIlionxCloudiliona-store-packagesvenvlibsite-packagesanyio_backends_asyncio.py", line 743, in run
    result = func(*args)
  File "C:/source/IlionxCloud/iliona-store-packages/store-packages/main.py", line 49, in process_results
    results = packageClient.query_packages_storage("PartitionKey eq 'app'")
  File "C:sourceIlionxCloudiliona-store-packagesstore-packagesclientAzureTableEntityQueryClient.py", line 39, in query_packages_storage
    for entity in entities:
TypeError: 'AbbreviatedPackage' object is not iterable

Advertisement

Answer

Your AbbreviatedPackage object can’t be converted to JSON automatically. When you run json.dumps with your list of AbbreviatedPackage objects they shouldn’t be serializable by default, throwing this error (as each object is trying to be iterated over and does not have an __iter__ method).

A few options:

  1. Use the .__dict__ method for your object when appending to your list. I personally don’t like this solution, as it’s uncontrolled.
  2. Write __iter__, __str__, and __repr__ methods to properly serialize to JSON along with a CustomEncoder for the json.dumps cls attribute:
# https://changsin.medium.com/how-to-serialize-a-class-object-to-json-in-python-849697a0cd3#8273

class Label:
    def __init__(self, label, x, y, width, height):
        self.label = label
        self.x = x
        self.y = y
        self.width = width
        self.height = height

    def __iter__(self):
        yield {
            "label": self.label,
            "x": self.x,
            "y": self.y,
            "width": self.width,
            "height": self.height
        }

    def __str__(self):
        return json.dumps(self, ensure_ascii=False, cls=CustomEncoder)

    def __repr__(self):
        return self.__str__()


Reference: https://changsin.medium.com/how-to-serialize-a-class-object-to-json-in-python-849697a0cd3#8273

And the CustomEncoder class:

import json

class CustomEncoder(json.JSONEncoder):
    def default(
        self,
        o,
    ):
        """
        A custom default encoder.
        In reality this should work for nearly any iterable.
        """
        try:
            iterable = iter(o)
        except TypeError:
            pass
        else:
            return list(iterable)
        # Let the base class default method raise the TypeError
        return json.JSONEncoder.default(self, o)

I did a full synthesis on this with code:

Advertisement