pythontkinter

Python - API request works in __init__ but not in function


im implementing api requests to my tkinter app. At the Gui Class init there is one api request running that works without problems. But when im calling a function inside the class that is running the same api request im getting back an error.

I'm not quite sure if it is the API or maybe my class structure.

My folder structure looks like this

Project Folder/
api/
    __init__.py
    api.py
gui/
    __init__.py
    gui.py
main.py

The main.py holds the Gui Class with the mainloop.

from gui.gui import Gui


if __name__ == '__main__':
    app = Gui()
    app.mainloop()

The GUI class contains the tkinter app and is inherited from customtkinter.CTk. Simplified it looks like that

import logging

import PIL.Image
from tkinter import *
import tkinter.messagebox
import customtkinter

from api.api import WikiApi


class Gui(customtkinter.CTk):
def __init__(self):
    super().__init__()

    # API
    self.api = WikiApi()
    self.book_list = self.api.get_all_books_from_shelv()['books'] # Fetching all book names from api

    # API Output looks like this
    '''
    {
        'books': [{
                'id': 37,
                'name': 'book-1',
                'slug': 'book-1',
                'description': '',
                'created_at': '2023-04-11T09:16:19.000000Z',
                'updated_at': '2023-04-14T08:40:49.000000Z',
                'created_by': 16,
                'updated_by': 4,
                'owned_by': 16
            }, {
                'id': 38,
                'name': 'book-2',
                'slug': 'book-2',
                'description': '',
                'created_at': '2023-04-13T07:07:23.000000Z',
                'updated_at': '2023-04-13T07:07:23.000000Z',
                'created_by': 16,
                'updated_by': 16,
                'owned_by': 16
            }
        ]
    }
    '''

    # logger
    # screen constants
    # root window attributes & widgets

    # refresh button that calls self.refresh_book_list

def refresh_book_list(self):
    self.book_list.clear()
    self.book_list = [book['name'] for book in self.api.get_all_books_from_shelv()['books']]
    # API response from function
    '''
    {
        'error': {
            'code': 403,
            'message': 'The owner of the used API token does not have permission to make API calls'
        }
    }
    '''

The api.py contains the class WikiApi and simplified looks like this

import requests
import logging
import json


class WikiApi:
    def __init__(self):
        self.TOKEN_ID = 'abcdef123'
        self.TOKEN_SECRET = 'password'

        self.HEADER = {
            "Authorization": f"Token {self.TOKEN_ID}:{self.TOKEN_SECRET}",
            "Accept": "application/vnd.api+json"
        }

        self.session = requests.session()
        self.session.headers = self.HEADER
        
    def _get(self, url):
        
        response = self.session.get(url)
        return response.json()
    
    
    def get_all_books_from_shelv(self):
        url = f'url to api endpoint'
        response = self._get(url)
        return response

Solution

  • It looks like (and you've seemingly confirmed) that the issue has to do with state retained in the requests.session() between the two API calls.

    To get more precise details about precisely why involves diving into the requests.session() implementation or docs for details.

    IIRC, requests has an extra-verbose way of "logging prepared requests" that can help you at this point.