Legacy Dev Forum Posts

 View Only

Sign Up

Unable to Call the Analytics Conversations Details Query with Dimension and Metric filters via Python SDK

  • 1.  Unable to Call the Analytics Conversations Details Query with Dimension and Metric filters via Python SDK

    Posted 06-05-2025 18:09

    Davis_Walker | 2023-07-10 19:01:13 UTC | #1

    We are working on a nightly script that gets a list of conversation Id's for the previous day, we are able to filter on dimensions, or metrics, however we cannot filter on both of them at the same time.

    Here's a snippet of the code in question:

    api_instance = PureCloudPlatformClientV2.AnalyticsApi(authToken)

    query = PureCloudPlatformClientV2.ConversationQuery()

    query.interval = "2023-07-03T04:00:00.000Z/2023-07-07T04:00:00.000Z" query.paging = PureCloudPlatformClientV2.PagingSpec()

    query.paging.pagenumber = '1' query.paging.pagesize = '2'

    query.conversationfilters = [PureCloudPlatformClientV2.ConversationDetailQueryFilter()] query.conversationfilters[0].type = "and"

    query.conversationfilters[0].clauses = [PureCloudPlatformClientV2.ConversationDetailQueryClause()] query.conversationfilters[0].clauses[0].type = "and" query.conversation_filters[0].clauses[0].predicates = [PureCloudPlatformClientV2.ConversationDetailQueryPredicate()] * 5

    query.conversationfilters[0].clauses[0].predicates[0].type = "dimension" query.conversationfilters[0].clauses[0].predicates[0].dimension = "divisionId" query.conversationfilters[0].clauses[0].predicates[0].operator = "matches" query.conversationfilters[0].clauses[0].predicates[0].value = "5338ce2b-8a04-4b0e-bea2-cb8b24ad76aa"

    query.conversationfilters[0].clauses[0].predicates[1].type = "dimension" query.conversationfilters[0].clauses[0].predicates[1].dimension = "originatingDirection" query.conversationfilters[0].clauses[0].predicates[1].operator = "matches" query.conversationfilters[0].clauses[0].predicates[1].value = "inbound" query.conversationfilters[0].clauses[0].predicates[2].type = "metric" query.conversationfilters[0].clauses[0].predicates[2].metric = "tTalk" query.conversationfilters[0].clauses[0].predicates[2].range = PureCloudPlatformClientV2.NumericRange() query.conversationfilters[0].clauses[0].predicates[2].range.gt = "60000"

    query.conversationfilters[0].clauses[0].predicates[3].type = "metric" query.conversationfilters[0].clauses[0].predicates[3].metric = "nBlindTransferred" query.conversationfilters[0].clauses[0].predicates[3].operator = "notExists" query.conversationfilters[0].clauses[0].predicates[3].value = None query.conversation_filters[0].clauses[0].predicates[3].range = None

    query.conversationfilters[0].clauses[0].predicates[4].type = "metric" query.conversationfilters[0].clauses[0].predicates[4].metric = "nConsultTransferred" query.conversationfilters[0].clauses[0].predicates[4].operator = "notExists" query.conversationfilters[0].clauses[0].predicates[4].value = None query.conversation_filters[0].clauses[0].predicates[4].range = None

    When running these filters we get the error:

    Traceback (most recent call last): File "c:\Users\...\gcConversationSearch.py", line 41, in <module> query.conversationfilters[0].clauses[0].predicates[2].dimension = None File "C:\Users\...\AppData\Roaming\Python\Python310\site-packages\PureCloudPlatformClientV2\models\conversationdetailquerypredicate.py", line 115, in dimension if dimension.lower() not in map(str.lower, allowedvalues): AttributeError: 'NoneType' object has no attribute 'lower' PS C:\Users\maxwed2> & "C:/Program Files/Python310/python.exe" "c:/Users/maxwed2/OneDrive - Nationwide/Desktop/gcConversationSearch.py" Traceback (most recent call last): File "c:\Users\...\Desktop\gcConversationSearch.py", line 98, in <module> apiresponse = apiinstance.postanalyticsconversationsdetailsquery(query) File "C:\Users\...\AppData\Roaming\Python\Python310\site-packages\PureCloudPlatformClientV2\apis\analyticsapi.py", line 2542, in postanalyticsconversationsdetailsquery response = self.apiclient.callapi(resourcepath, 'POST', File "C:\Users\...\AppData\Roaming\Python\Python310\site-packages\PureCloudPlatformClientV2\apiclient.py", line 530, in callapi return self._callapi(resourcepath, method, File "C:\Users\...\AppData\Roaming\Python\Python310\site-packages\PureCloudPlatformClientV2\apiclient.py", line 343, in _callapi responsedata = self.request(method, url, queryparams=queryparams, File "C:\Users\...\AppData\Roaming\Python\Python310\site-packages\PureCloudPlatformClientV2\apiclient.py", line 565, in request return self.restclient.POST(url, File "C:\Users\...\AppData\Roaming\Python\Python310\site-packages\PureCloudPlatformClientV2\rest.py", line 225, in POST return self.request("POST", url, File "C:\Users\...\AppData\Roaming\Python\Python310\site-packages\PureCloudPlatformClientV2\rest.py", line 197, in request raise ApiException(httpresp=r) PureCloudPlatformClientV2.rest.ApiException: (400) Reason: Bad Request HTTP response headers: HTTPHeaderDict({'Content-Type': 'application/json', 'Content-Length': '195', 'Connection': 'keep-alive', 'Date': 'Mon, 10 Jul 2023 18:25:30 GMT', 'ININ-Correlation-Id': '3de06140-aac7-4c06-82f6-3ced2a917ecd', 'Strict-Transport-Security': 'max-age=600; includeSubDomains', 'Cache-Control': 'no-cache, no-store, must-revalidate', 'X-Cache': 'Error from cloudfront', 'Via': '1.1 8c2dc914428d194718c8f636a78a5f74.cloudfront.net (CloudFront)', 'X-Amz-Cf-Pop': 'DFW57-P3', 'X-Amz-Cf-Id': 'NoXTrlsOH05nps4qL0Bs8eaGjDs89BgGbf5dURLZoyx5oqupI_Ygg=='}) HTTP response body: {"message":"dimension must be null when using a metric predicate","code":"bad.request","status":400,"messageParams":{},"contextId":"3de06140-aac7-4c06-82f6-3ced2a917ecd","details":[],"errors":[]}

    The part that stands out is:

    HTTP response body: {"message":"dimension must be null when using a metric predicate","code":"bad.request","status":400,"messageParams":{},"contextId":"3de06140-aac7-4c06-82f6-3ced2a917ecd","details":[],"errors":[]}

    Based on this error "dimension must be null when using a metric predicate" we tried updating our code to have dimension = None like below for all of our metric types but hit another error (example just shows 1 of 3 places we updated it):

    query.conversationfilters[0].clauses[0].predicates[3].type = "metric" query.conversationfilters[0].clauses[0].predicates[3].metric = "nBlindTransferred" query.conversationfilters[0].clauses[0].predicates[3].operator = "notExists" query.conversationfilters[0].clauses[0].predicates[3].value = None query.conversationfilters[0].clauses[0].predicates[3].range = None query.conversationfilters[0].clauses[0].predicates[3].dimension = None

    It gives this error:

    When adding Dimension = None we get NoneType has not object .lower()

    We also originally weren't using "clauses" so if you remove any reference to "clauses" the exact same thing applies as I said above, we were just grasping at ideas to get this to work.

    In the definition for dimensions you have this:

    allowedvalues = ["conversationEnd", "conversationId", "conversationInitiator", "conversationStart", >"customerParticipation", "divisionId", "externalTag", "mediaStatsMinConversationMos", "originatingDirection"] if dimension.lower() not in map(str.lower, allowedvalues): # print("Invalid value for dimension -> " + dimension) self.dimension = "outdatedsdk_version"

    So it's not handling None/Null's and it seems like this is where the issue is coming from, however admittedly I've found the documentation on consuming this via python pretty lacking so I'm expecting we're doing something silly somewhere and hoping someone can help identify what's going on here. Like I said, if we only do Dimension filters, or only do Metric filters it works perfectly fine, only when we try to do both do things go haywire.


    tim.smith | 2023-07-10 19:05:13 UTC | #2

    I don't see a question in your post and it looks like you got a query working. But here are some resources relevant to analytics queries:


    Davis_Walker | 2023-07-10 19:29:12 UTC | #3

    The question is why am I getting the error, I tried doing as you described and here's our API Explorer Body we've been writing this based on

    { "conversationFilters": [ { "type": "and", "predicates": [ { "type": "dimension", "dimension": "divisionId", "value": "5338ce2b-8a04-4b0e-bea2-cb8b24ad76aa" }, { "type": "metric", "metric": "tTalk", "range": { "gt": 60000 } }, { "type": "dimension", "dimension": "originatingDirection", "operator": "matches", "value": "inbound" }, { "type": "metric", "metric": "nBlindTransferred", "operator": "notExists" }, { "type": "metric", "metric": "nConsultTransferred", "operator": "notExists" } ] } ], "interval": "2023-07-03T04:00:00.000Z/2023-07-07T04:00:00.000Z", "paging": { "pageSize": 100, "pageNumber": 1 } }

    And here's the actual query it's creating based on our code (without the clauses section since that matches our existing working query):

    {'aggregations': None, 'conversationfilters': [{'clauses': None, 'predicates': [{'dimension': 'originatingDirection', 'metric': 'nConsultTransferred', 'operator': 'notExists', 'range': None, 'type': 'metric', 'value': None}, {'dimension': 'originatingDirection', 'metric': 'nConsultTransferred', 'operator': 'notExists', 'range': None, 'type': 'metric', 'value': None}, {'dimension': 'originatingDirection', 'metric': 'nConsultTransferred', 'operator': 'notExists', 'range': None, 'type': 'metric', 'value': None}, {'dimension': 'originatingDirection', 'metric': 'nConsultTransferred', 'operator': 'notExists', 'range': None, 'type': 'metric', 'value': None}, {'dimension': 'originatingDirection', 'metric': 'nConsultTransferred', 'operator': 'notExists', 'range': None, 'type': 'metric', 'value': None}], 'type': 'and'}], 'evaluationfilters': None, 'interval': '2023-07-03T04:00:00.000Z/2023-07-07T04:00:00.000Z', 'order': None, 'orderby': None, 'paging': {'pagenumber': '1', 'pagesize': '2'}, 'resolutionfilters': None, 'segmentfilters': None, 'surveyfilters': None}

    Now to figure out why it's overwriting all of the existing data each time we set an additional predicate rather than appending each one to the list.

    query.conversationfilters[0].predicates[0].type = "dimension" query.conversationfilters[0].predicates[0].dimension = "divisionId" query.conversationfilters[0].predicates[0].operator = "matches" query.conversationfilters[0].predicates[0].value = "5338ce2b-8a04-4b0e-bea2-cb8b24ad76aa"

    query.conversationfilters[0].predicates[1].type = "dimension" query.conversationfilters[0].predicates[1].dimension = "originatingDirection" query.conversationfilters[0].predicates[1].operator = "matches" query.conversationfilters[0].predicates[1].value = "inbound"

    query.conversationfilters[0].predicates[2].type = "metric" query.conversationfilters[0].predicates[2].metric = "tTalk" query.conversationfilters[0].predicates[2].range = PureCloudPlatformClientV2.NumericRange() query.conversationfilters[0].predicates[2].range.gt = "60000"

    query.conversationfilters[0].predicates[3].type = "metric" query.conversationfilters[0].predicates[3].metric = "nBlindTransferred" query.conversationfilters[0].predicates[3].operator = "notExists" query.conversationfilters[0].predicates[3].value = None query.conversation_filters[0].predicates[3].range = None

    query.conversationfilters[0].predicates[4].type = "metric" query.conversationfilters[0].predicates[4].metric = "nConsultTransferred" query.conversationfilters[0].predicates[4].operator = "notExists" query.conversationfilters[0].predicates[4].value = None query.conversation_filters[0].predicates[4].range = None

    Admittedly this is my first time working with something like this, and I'm much more familiar w/ Node JS, however this solution is required to be in python so I'm probably doing something stupid as originally mentioned. We're going to update our code to try using append instead of what we're doing above and see if that improves things.


    tim.smith | 2023-07-10 19:47:26 UTC | #4

    quote="tim.smith, post:2, topic:20929"] Validate your request object that you've constructed by serializing it to JSON using [ApiClient.sanitize_for_serialization. This JSON object is what gets sent to the API and should exactly match the JSON object you created in API Explorer. [/quote]

    @Davis_Walker can you do this and share the result? The second block you shared above is a dump of a python object, not serialization to JSON using the SDK's logic.

    DavisWalker, post:1, topic:20929
    query.conversationfilters[0].clauses[0].predicates = [PureCloudPlatformClientV2.ConversationDetailQueryPredicate()] * 5

    The problem you're experiencing seems like every array element has the same object reference. I'm not a python developer either, but multiplying an array by 5 and expecting that to result in instantiating 5 separate objects seems suspect. But python's syntax is generally pretty suspect, so maybe that's ok. What happens if you instantiate each one manually like query.conversation_filters[0].clauses[0].predicates = [PureCloudPlatformClientV2.ConversationDetailQueryPredicate(), PureCloudPlatformClientV2.ConversationDetailQueryPredicate(), PureCloudPlatformClientV2.ConversationDetailQueryPredicate(), PureCloudPlatformClientV2.ConversationDetailQueryPredicate(), PureCloudPlatformClientV2.ConversationDetailQueryPredicate()] (I assume that's valid syntax)? Or append to the array in each predicate block like query.conversation_filters[0].clauses[0].predicates.append(PureCloudPlatformClientV2.ConversationDetailQueryPredicate()).


    Davis_Walker | 2023-07-10 20:30:20 UTC | #5

    Yup, after updating the code to use append and redefining the value each time things are now working as expected, here's the updated part of the code in case someone comes across this while googling similar issues

    conversationfilter = PureCloudPlatformClientV2.ConversationDetailQueryFilter() conversationfilter.type = "and" conversation_filter.predicates = []

    predicate = PureCloudPlatformClientV2.ConversationDetailQueryPredicate() predicate.type = "dimension" predicate.dimension = "divisionId" predicate.operator = "matches" predicate.value = "5338ce2b-8a04-4b0e-bea2-cb8b24ad76aa"

    conversation_filter.predicates.append(predicate)

    predicate = PureCloudPlatformClientV2.ConversationDetailQueryPredicate() predicate.type = "dimension" predicate.dimension = "originatingDirection" predicate.operator = "matches" predicate.value = "inbound"

    conversation_filter.predicates.append(predicate)

    predicate = PureCloudPlatformClientV2.ConversationDetailQueryPredicate() predicate.type = "metric" predicate.metric = "tTalk" range_ = PureCloudPlatformClientV2.NumericRange() range.gt = 60000 predicate.range = range

    conversation_filter.predicates.append(predicate)

    predicate = PureCloudPlatformClientV2.ConversationDetailQueryPredicate() predicate.type = "metric" predicate.metric = "nBlindTransferred" predicate.operator = "notExists"

    conversation_filter.predicates.append(predicate)

    predicate = PureCloudPlatformClientV2.ConversationDetailQueryPredicate() predicate.type = "metric" predicate.metric = "nConsultTransferred" predicate.operator = "notExists"

    conversation_filter.predicates.append(predicate)

    query.conversationfilters.append(conversationfilter)

    Edit: I like your idea of putting them each in the initial array, instead of what I posted above, for now this is working so I'm not going to spend much more time on it right now, but may have to give that a try later.


    tim.smith | 2023-07-17 17:33:00 UTC | #6


    This post was migrated from the old Developer Forum.

    ref: 20929