Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AttributeError: 'str' object has no attribute 'update' when running get_authentication_events #533

Open
technomanxer opened this issue Apr 4, 2022 · 6 comments
Labels

Comments

@technomanxer
Copy link

Describe the bug

I'm getting AttributeError: 'str' object has no attribute 'update' when I try to retrieve & process user.get_authentication_events()

To Reproduce

Steps to reproduce the behavior:
Run the following code after setting up Canvas object & retrieving single user

user_logins = user.get_authentication_events(start_time="2022-04-03", end_date="2022-04-04")
for u in user_logins:
    print(u)

The code stops right before the print statement on the "for" line. get_authentication_events() returns a PaginatedList but it's not iterable for some reason. Unless I'm missing something. Debug logs are showing that it retrieves the data from the REST API once I start the for loop (I can supply that log upon request)

Expected behavior

I should be able to loop through this PaginatedList object like every other PaginatedList object in Canvas API.

Environment information

  • Python version (python --version): Python 3.10.2
  • CanvasAPI version (pip show canvasapi):
    Name: canvasapi
    Version: 2.2.0
    Summary: API wrapper for the Canvas LMS
    Home-page: https://github.com/ucfopen/canvasapi
    Author: University of Central Florida - Center for Distributed Learning
    Author-email: [email protected]

Additional context

Here is the stack trace (sanitized personal info/paths as much as possible)

@bennettscience
Copy link
Contributor

I just tried and got the same result, testing against myself (so I know I had a login). Here's the method in the User object.

Canvas is returning data from https://{{domain}}/api/v1/audit/authentication/users/:user_id to Postman. I don't have time to look deeper, but you could try setting up a Requester instance and testing it directly. I can try some other testing later this week.

@bennettscience
Copy link
Contributor

bennettscience commented Apr 4, 2022

Nevermind, figured it out.

Canvas returns an object with nested links and events objects. The library expects events, but when you iterate the PaginatedList, links doesn't have the correct structure and it can't build the AuthenticationEvent instance.

Because it's returned as a PaginatedList, I can't think of a way to extract the data using this version without iterating directly. You can patch your local version of canvasapi to return JSON (see here for an example of how) until I can get a PR together. Or, write your own function using a Requester instance to handle the API call.

@technomanxer
Copy link
Author

Wow, thank you @bennettscience. Appreciate the insight & prompt response!

I'll probably write my own function to get the API call going for now with Requester.

@jessemcbride
Copy link
Member

jessemcbride commented Apr 4, 2022

PaginatedList can be passed a _root keyword argument to tell it what key to build the list from. If you want to keep working with AuthenticationEvent objects instead of parsing JSON, you might be able to get away with something like this:

def get_authentication_events(self, **kwargs):
    """
    List authentication events for a given user.
    :calls: `GET /api/v1/audit/authentication/users/:user_id \
    <https://canvas.instructure.com/doc/api/authentications_log.html#method.authentication_audit_api.for_user>`_
    :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
            :class:`canvasapi.authentication_event.AuthenticationEvent`
    """
    from canvasapi.authentication_event import AuthenticationEvent

    return PaginatedList(
        AuthenticationEvent,
        self._requester,
        "GET",
        "audit/authentication/users/{}".format(self.id),
        _kwargs=combine_kwargs(**kwargs),
        _root="events"
    )
    
canvasapi.user.User.get_authentication_events = get_authentication_events

@bennettscience
Copy link
Contributor

Ah, I forgot about _root! @jessemcbride, I think I've even asked you about that argument in the past.

I'd do that instead ☝️ .

@technomanxer
Copy link
Author

Thanks @jessemcbride. Just FYI your patch now triggers AttributeError: 'AuthenticationEvent' object has no attribute 'pseudonym_id' in canvas_object.py.

I had to go into authentication_event.py

return "{} {} ({})".format(self.created_at, self.event_type, self.pseudonym_id)
and patch that to the following line:
return "{} {} ({})".format(self.created_at, self.event_type, self.id) for the object to be formed.

Otherwise it works great and is returning exactly what I need in the object.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants