Skip to content

Instantly share code, notes, and snippets.

@jessemcbride
Created November 8, 2019 19:23

Paginated List Rework

Requirements

  • Try to retain backwards compatibility
  • Leave room for multithreading implementations
  • Implement __len__()
    • Handle negative indices
    • Fail gracefully when unsupported
  • Support lists containing multiple CanvasObject types
    • For example: Listing a user's activity stream
  • Support "Compound Documents"
  • Provide an option to avoid element caching

Basic Framework

class PaginatedList:
	
	def __init__(self,
		requester,
		endpoint,
		method="GET",
		extra_attributes=None,
		per_page=100,
		content_class=CanvasObject,
		**kwargs
	):
		self.requester = requester

		# Identify link headers
		self.pages = {
			0: self.get_first_page(),
		}
		
		self.last_link = self.pages[0].links.get("last")
		self.pages[current] = [] # the data
		
	def __len__(self):
		if self.last_link:
		    return compute_length(first, data)
		raise NotImplementedError("Cast this to list() first")
	
	def compute_length(self):
		"""
		1. Grab the first page results
		2. If the first page == last page, just return len of the first page.
		3. Grab the last page and count the items on the last page
		4. Calculate the number of items in between ((last_page_number - first_page_number) * per_page)
		5. Return the sum of steps 3 and 4
		"""
		if self.get_page_number(self.first_link) == self.last_link:
			return len(self.pages[self.first_link])
	
		data = self.get_page(self.last_link)
		self.pages[self.last_link] = data
	
		pages = self.last_link - self.first_link
		items = (pages - 1) * per_page
		return items + len(self.pages[self.last_link])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment