Skip to content

user_attributes

user_attributes

UserAttributes_IssuerType

Bases: DomoEnumMixin, Enum

Types of user attribute issuers.

clean_attribute_id

clean_attribute_id(text: str) -> str

Clean attribute ID by removing non-alphanumeric characters.

Parameters:

Name Type Description Default
text str

Text to clean

required

Returns:

Name Type Description
str str

Cleaned text with only alphanumeric characters

Source code in src/crew_dcs/routes/instance_config/user_attributes.py
67
68
69
70
71
72
73
74
75
76
def clean_attribute_id(text: str) -> str:
    """Clean attribute ID by removing non-alphanumeric characters.

    Args:
        text: Text to clean

    Returns:
        str: Cleaned text with only alphanumeric characters
    """
    return re.sub(r"[^A-Za-z0-9]", "", text)

create_user_attribute async

create_user_attribute(
    auth: DomoAuth,
    attribute_id: str,
    name: str | None = None,
    description: str | None = None,
    data_type: str | None = None,
    security_voter: str | None = None,
    issuer_type: UserAttributes_IssuerType | None = None,
    return_raw: bool = False,
    *,
    context: RouteContext | None = None,
    **context_kwargs
) -> ResponseGetData

Create a new user attribute.

Parameters:

Name Type Description Default
auth DomoAuth

Authentication object

required
attribute_id str

Unique identifier for the attribute (will be cleaned)

required
name str | None

Display name for the attribute (defaults to attribute_id)

None
description str | None

Description of the attribute (defaults to timestamp)

None
data_type str | None

Data type validator (default: "ANY_VALUE")

None
security_voter str | None

Security voter setting (default: "FULL_VIS_ADMIN_IDP")

None
issuer_type UserAttributes_IssuerType | None

Type of issuer (default: CUSTOM)

None
return_raw bool

Return raw API response without processing

False
context RouteContext | None

RouteContext for request configuration

None
**context_kwargs

Additional context parameters (session, debug_api, etc.)

{}

Returns:

Type Description
ResponseGetData

ResponseGetData object confirming attribute creation

Raises:

Type Description
UserAttributes_CRUD_Error

If attribute creation fails

Source code in src/crew_dcs/routes/instance_config/user_attributes.py
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
@gd.route_function
@log_call(
    level_name="route",
    config=LogDecoratorConfig(
        entity_extractor=DomoEntityExtractor(),
        result_processor=DomoEntityResultProcessor(),
    ),
)
async def create_user_attribute(
    auth: DomoAuth,
    attribute_id: str,
    name: str | None = None,
    description: str | None = None,
    data_type: str | None = None,
    security_voter: str | None = None,
    issuer_type: UserAttributes_IssuerType | None = None,
    return_raw: bool = False,
    *,
    context: RouteContext | None = None,
    **context_kwargs,
) -> rgd.ResponseGetData:
    """Create a new user attribute.

    Args:
        auth: Authentication object
        attribute_id: Unique identifier for the attribute (will be cleaned)
        name: Display name for the attribute (defaults to attribute_id)
        description: Description of the attribute (defaults to timestamp)
        data_type: Data type validator (default: "ANY_VALUE")
        security_voter: Security voter setting (default: "FULL_VIS_ADMIN_IDP")
        issuer_type: Type of issuer (default: CUSTOM)
        return_raw: Return raw API response without processing
        context: RouteContext for request configuration
        **context_kwargs: Additional context parameters (session, debug_api, etc.)

    Returns:
        ResponseGetData object confirming attribute creation

    Raises:
        UserAttributes_CRUD_Error: If attribute creation fails
    """
    context = RouteContext.build_context(context=context, **context_kwargs)

    name = name or attribute_id
    attribute_id = clean_attribute_id(attribute_id)
    description = (
        description
        or f"updated via domolibrary {dt.datetime.now().strftime('%Y-%m-%d - %H:%M')}"
    )
    data_type = data_type or "ANY_VALUE"
    security_voter = security_voter or "FULL_VIS_ADMIN_IDP"
    issuer_type = issuer_type or UserAttributes_IssuerType.CUSTOM

    body = generate_create_user_attribute_body(
        attribute_id=attribute_id,
        issuer_type=issuer_type,
        name=name,
        data_type=data_type,
        security_voter=security_voter,
        description=description,
    )

    url = f"https://{auth.domo_instance}.domo.com/api/user/v1/properties/meta/keys/{attribute_id}"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="POST",
        body=body,
        context=context,
    )

    if return_raw:
        return res

    if not res.is_success:
        raise UserAttributes_CRUD_Error(
            operation="create",
            attribute_id=attribute_id,
            message=f"Bad Request - does attribute {attribute_id} already exist?",
            res=res,
        )

    res.response = f"created {attribute_id}"

    return res

delete_user_attribute async

delete_user_attribute(
    auth: DomoAuth,
    attribute_id: str,
    return_raw: bool = False,
    *,
    context: RouteContext | None = None,
    **context_kwargs
) -> ResponseGetData

Delete a user attribute.

Parameters:

Name Type Description Default
auth DomoAuth

Authentication object

required
attribute_id str

ID of the attribute to delete

required
return_raw bool

Return raw API response without processing

False
context RouteContext | None

RouteContext for request configuration

None
**context_kwargs

Additional context parameters (session, debug_api, etc.)

{}

Returns:

Type Description
ResponseGetData

ResponseGetData object confirming attribute deletion

Raises:

Type Description
UserAttributes_CRUD_Error

If attribute deletion fails

Source code in src/crew_dcs/routes/instance_config/user_attributes.py
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
@gd.route_function
@log_call(
    level_name="route",
    config=LogDecoratorConfig(
        entity_extractor=DomoEntityExtractor(),
        result_processor=DomoEntityResultProcessor(),
    ),
)
async def delete_user_attribute(
    auth: DomoAuth,
    attribute_id: str,
    return_raw: bool = False,
    *,
    context: RouteContext | None = None,
    **context_kwargs,
) -> rgd.ResponseGetData:
    """Delete a user attribute.

    Args:
        auth: Authentication object
        attribute_id: ID of the attribute to delete
        return_raw: Return raw API response without processing
        context: RouteContext for request configuration
        **context_kwargs: Additional context parameters (session, debug_api, etc.)

    Returns:
        ResponseGetData object confirming attribute deletion

    Raises:
        UserAttributes_CRUD_Error: If attribute deletion fails
    """
    context = RouteContext.build_context(context=context, **context_kwargs)

    url = f"https://{auth.domo_instance}.domo.com/api/user/v1/properties/meta/keys/{attribute_id}"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="DELETE",
        context=context,
    )

    if return_raw:
        return res

    if not res.is_success:
        raise UserAttributes_CRUD_Error(
            operation="delete",
            attribute_id=attribute_id,
            message=f"Bad Request - failed to delete {attribute_id}",
            res=res,
        )

    res.response = f"deleted {attribute_id}"

    return res

generate_create_user_attribute_body

generate_create_user_attribute_body(
    attribute_id: str,
    name: str | None = None,
    description: str | None = None,
    issuer_type: UserAttributes_IssuerType | None = None,
    security_voter: str | None = None,
    data_type: str | None = None,
) -> dict

Generate request body for creating user attributes.

Parameters:

Name Type Description Default
attribute_id str

Unique identifier for the attribute

required
name str | None

Display name for the attribute

None
description str | None

Description of the attribute

None
issuer_type UserAttributes_IssuerType | None

Type of issuer for the attribute (UserAttributes_IssuerType enum)

None
security_voter str | None

Security voter setting

None
data_type str | None

Data type validator

None

Returns:

Name Type Description
dict dict

Request body for attribute creation

Source code in src/crew_dcs/routes/instance_config/user_attributes.py
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
def generate_create_user_attribute_body(
    attribute_id: str,
    name: str | None = None,
    description: str | None = None,
    issuer_type: UserAttributes_IssuerType | None = None,
    security_voter: str | None = None,
    data_type: str | None = None,
) -> dict:
    """Generate request body for creating user attributes.

    Args:
        attribute_id: Unique identifier for the attribute
        name: Display name for the attribute
        description: Description of the attribute
        issuer_type: Type of issuer for the attribute (UserAttributes_IssuerType enum)
        security_voter: Security voter setting
        data_type: Data type validator

    Returns:
        dict: Request body for attribute creation
    """
    s = {"key": attribute_id}

    if issuer_type:
        s.update({"keyspace": issuer_type.value})

    if security_voter:
        s.update({"securityVoter": security_voter})

    if data_type:
        s.update({"validator": data_type})

    if name:
        s.update({"title": name})

    if description:
        s.update({"description": description})

    return s

get_user_attribute_by_id async

get_user_attribute_by_id(
    auth: DomoAuth,
    attribute_id: str,
    return_raw: bool = False,
    *,
    context: RouteContext | None = None,
    **context_kwargs
) -> ResponseGetData

Retrieve a specific user attribute by ID.

Parameters:

Name Type Description Default
auth DomoAuth

Authentication object

required
attribute_id str

ID of the attribute to retrieve

required
return_raw bool

Return raw API response without processing

False
context RouteContext | None

RouteContext for request configuration

None
**context_kwargs

Additional context parameters (session, debug_api, etc.)

{}

Returns:

Type Description
ResponseGetData

ResponseGetData object containing the user attribute

Raises:

Type Description
UserAttributes_GET_Error

If attribute retrieval fails or attribute not found

Source code in src/crew_dcs/routes/instance_config/user_attributes.py
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
@gd.route_function
@log_call(
    level_name="route",
    config=LogDecoratorConfig(
        entity_extractor=DomoEntityExtractor(),
        result_processor=DomoEntityResultProcessor(),
    ),
)
async def get_user_attribute_by_id(
    auth: DomoAuth,
    attribute_id: str,
    return_raw: bool = False,
    *,
    context: RouteContext | None = None,
    **context_kwargs,
) -> rgd.ResponseGetData:
    """Retrieve a specific user attribute by ID.

    Args:
        auth: Authentication object
        attribute_id: ID of the attribute to retrieve
        return_raw: Return raw API response without processing
        context: RouteContext for request configuration
        **context_kwargs: Additional context parameters (session, debug_api, etc.)

    Returns:
        ResponseGetData object containing the user attribute

    Raises:
        UserAttributes_GET_Error: If attribute retrieval fails or attribute not found
    """

    # Create a new context with incremented debug_num_stacks_to_drop for nested call
    context = RouteContext.build_context(context, **context_kwargs)

    res = await get_user_attributes(
        auth=auth,
        context=context,
        return_raw=return_raw,
    )

    if return_raw:
        return res

    if not res.is_success:
        raise UserAttributes_GET_Error(attribute_id=attribute_id, res=res)

    res.response = next(
        (obj for obj in res.response if obj["key"] == attribute_id), None
    )

    if not res.response:
        raise UserAttributes_GET_Error(
            attribute_id=attribute_id,
            message=f"attribute {attribute_id} not found",
            res=res,
        )

    return res

get_user_attributes async

get_user_attributes(
    auth: DomoAuth,
    issuer_type_ls: (
        list[UserAttributes_IssuerType] | None
    ) = None,
    return_raw: bool = False,
    *,
    context: RouteContext | None = None,
    **context_kwargs
) -> ResponseGetData

Retrieve user attributes from Domo instance.

User attributes can be of different types: IDP, domo-defined, or customer-defined. Note: API does not filter on the issuer type despite accepting filter parameter, so filtering is done client-side.

Parameters:

Name Type Description Default
auth DomoAuth

Authentication object

required
issuer_type_ls list[UserAttributes_IssuerType] | None

list of issuer types to retrieve (default: all types)

None
return_raw bool

Return raw API response without processing

False
context RouteContext | None

RouteContext for request configuration

None
**context_kwargs

Additional context parameters (session, debug_api, etc.)

{}

Returns:

Type Description
ResponseGetData

ResponseGetData object containing user attributes

Raises:

Type Description
UserAttributes_GET_Error

If user attributes retrieval fails

Source code in src/crew_dcs/routes/instance_config/user_attributes.py
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
@gd.route_function
@log_call(
    level_name="route",
    config=LogDecoratorConfig(
        entity_extractor=DomoEntityExtractor(),
        result_processor=DomoEntityResultProcessor(),
    ),
)
async def get_user_attributes(
    auth: DomoAuth,
    issuer_type_ls: (
        list[UserAttributes_IssuerType] | None
    ) = None,  # use `UserAttributes_IssuerType` enum
    return_raw: bool = False,
    *,
    context: RouteContext | None = None,
    **context_kwargs,
) -> rgd.ResponseGetData:
    """Retrieve user attributes from Domo instance.

    User attributes can be of different types: IDP, domo-defined, or customer-defined.
    Note: API does not filter on the issuer type despite accepting filter parameter,
    so filtering is done client-side.

    Args:
        auth: Authentication object
        issuer_type_ls: list of issuer types to retrieve (default: all types)
        return_raw: Return raw API response without processing
        context: RouteContext for request configuration
        **context_kwargs: Additional context parameters (session, debug_api, etc.)

    Returns:
        ResponseGetData object containing user attributes

    Raises:
        UserAttributes_GET_Error: If user attributes retrieval fails
    """
    context = RouteContext.build_context(context=context, **context_kwargs)

    issuer_type_ls = issuer_type_ls or list(UserAttributes_IssuerType)

    issuer_types = ",".join([dmue.normalize_enum(member) for member in issuer_type_ls])

    params = {"issuerTypes": issuer_types}

    url = f"https://{auth.domo_instance}.domo.com/api/user/v1/properties/meta/keys"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="GET",
        params=params,
        context=context,
    )

    if return_raw:
        return res

    if not res.is_success:
        raise UserAttributes_GET_Error(res=res)

    res.response = [
        obj
        for obj in res.response
        if obj["keyspace"] in [dmue.normalize_enum(member) for member in issuer_type_ls]
    ]

    return res

update_user_attribute async

update_user_attribute(
    auth: DomoAuth,
    attribute_id: str,
    name: str | None = None,
    description: str | None = None,
    issuer_type: UserAttributes_IssuerType = CUSTOM,
    data_type: str | None = None,
    security_voter: str | None = None,
    return_raw: bool = False,
    *,
    context: RouteContext | None = None,
    **context_kwargs
) -> ResponseGetData

Update an existing user attribute.

The body must include all attribute parameters. This function will use the get_user_attribute_by_id function to retrieve existing values and merge them with the provided updates.

Parameters:

Name Type Description Default
auth DomoAuth

Authentication object

required
attribute_id str

ID of the attribute to update

required
name str | None

Display name for the attribute

None
description str | None

Description of the attribute

None
issuer_type UserAttributes_IssuerType

Type of issuer (default: CUSTOM)

CUSTOM
data_type str | None

Data type validator

None
security_voter str | None

Security voter setting

None
return_raw bool

Return raw API response without processing

False
context RouteContext | None

RouteContext for request configuration

None
**context_kwargs

Additional context parameters (session, debug_api, etc.)

{}

Returns:

Type Description
ResponseGetData

ResponseGetData object confirming attribute update

Raises:

Type Description
UserAttributes_CRUD_Error

If attribute update fails

UserAttributes_GET_Error

If attribute to update is not found

Source code in src/crew_dcs/routes/instance_config/user_attributes.py
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
@gd.route_function
@log_call(
    level_name="route",
    config=LogDecoratorConfig(
        entity_extractor=DomoEntityExtractor(),
        result_processor=DomoEntityResultProcessor(),
    ),
)
async def update_user_attribute(
    auth: DomoAuth,
    attribute_id: str,
    name: str | None = None,
    description: str | None = None,
    issuer_type: UserAttributes_IssuerType = UserAttributes_IssuerType.CUSTOM,
    data_type: str | None = None,
    security_voter: str | None = None,
    return_raw: bool = False,
    *,
    context: RouteContext | None = None,
    **context_kwargs,
) -> rgd.ResponseGetData:
    """Update an existing user attribute.

    The body must include all attribute parameters. This function will use the
    `get_user_attribute_by_id` function to retrieve existing values and merge
    them with the provided updates.

    Args:
        auth: Authentication object
        attribute_id: ID of the attribute to update
        name: Display name for the attribute
        description: Description of the attribute
        issuer_type: Type of issuer (default: CUSTOM)
        data_type: Data type validator
        security_voter: Security voter setting
        return_raw: Return raw API response without processing
        context: RouteContext for request configuration
        **context_kwargs: Additional context parameters (session, debug_api, etc.)

    Returns:
        ResponseGetData object confirming attribute update

    Raises:
        UserAttributes_CRUD_Error: If attribute update fails
        UserAttributes_GET_Error: If attribute to update is not found
    """

    body = generate_create_user_attribute_body(
        attribute_id=attribute_id,
        issuer_type=issuer_type,
        name=name,
        description=description,
        data_type=data_type,
        security_voter=security_voter,
    )

    # Create a new context with incremented debug_num_stacks_to_drop for nested call
    context = RouteContext.build_context(context, **context_kwargs)

    res = await get_user_attribute_by_id(
        attribute_id=attribute_id,
        auth=auth,
        context=context,
        return_raw=return_raw,
    )

    if return_raw:
        return res

    body = {**res.response, **body}

    url = f"https://{auth.domo_instance}.domo.com/api/user/v1/properties/meta/keys/{attribute_id}"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="PUT",
        body=body,
        context=context,
    )

    if return_raw:
        return res

    if not res.is_success:
        raise UserAttributes_CRUD_Error(
            operation="update",
            attribute_id=attribute_id,
            message=f"Bad Request - error updating {attribute_id}",
            res=res,
        )

    res.response = f"updated {attribute_id}"

    return res