Why is `plone.api.content.find()` not returning the `context` object when `depth=1`?

What is actually the meaning of depth in plone.api.content.find?

plone.api.content.find() describes the depth parameter as

depth – How far in the content tree we want to search from context

For all values of depth but 1 find returns also the object in the context.

Why is plone.api.content.find() not returning the context object when depth == 1 but returning it when depth != 1? Is there any parameter to control it?

Is this a bug or a feature?

To reproduce it:

>>> from plone import api
>>> from zope.component.hooks import setSite
>>> setSite(app.get('Plone'))
>>> portal = api.portal.get()
>>> top_folder = api.content.create(type='Folder', title='top_folder', container=portal)
>>> sub_folder_1 = api.content.create(type='Folder', title='sub_folder_1', container=top_folder)
>>> sub_folder_2 = api.content.create(type='Folder', title='sub_folder_2', container=top_folder)
>>> api.content.transition(obj=top_folder, transition='publish')
>>> api.content.transition(obj=sub_folder_1, transition='publish')
>>> api.content.transition(obj=sub_folder_2, transition='publish')
>>> [x.getObject().title for x in api.content.find(context=top_folder, depth=0)]
>>> [x.getObject().title for x in api.content.find(context=top_folder, depth=1)]
['sub_folder_1', 'sub_folder_2']
>>> [x.getObject().title for x in api.content.find(context=top_folder, depth=2)]
['top_folder', 'sub_folder_1', 'sub_folder_2']
>>> [x.getObject().title for x in api.content.find(context=top_folder, depth=3)]
['top_folder', 'sub_folder_1', 'sub_folder_2']

1 Like

Looks like a bug to me.

However, it seems it is a bug in ZCatalog or the index being used, not in plone.api. I instrumented the code for api.content.find and found that the generated queries at each call are consistent:

{'path': {'query': '/Plone/top_folder', 'depth': 0}}
{'path': {'query': '/Plone/top_folder', 'depth': 1}}
{'path': {'query': '/Plone/top_folder', 'depth': 2}}

These are the queries passed to portal_catalog for each depth. Nothing suspicious.

In Products.ExtendedPathIndex the docstring of the search method says:

        depth let's you limit the results to items at most depth levels deeper
        than the matched path. depth == 0 means no subitems are included at
        all, with depth == 1 only direct children are included, etc.
        depth == -1, the default, returns all children at any depth.

So, with depth == 1 I would expect as result the top_folder plus its direct children. This is not what happens, as you noted and I confirmed.

The code for Products.ExtendendPathIndex seems to handle depths 0 and 1 as special cases (optimization). So I think this is a clue :slight_smile:. I'm not familiar with ZCatalog-related code, however.

This bug seems related: Inconsistent handling of "depth=1" for "level=0" versus "level>0"